动态代理

Smile_slime_47

代理模式


代理模式是一种设计模式,旨在不干涉原核心代码的基础上对原代码的功能进行增强。通常分为动态代理的静态代理两种实现。其中Spring AOP主要就是基于动态代理实现的切面功能。

动态代理(Dynamic Proxy)提供了一个实现方式,使得我们可以在代码中不去实现一个接口,而是在运行时去实现接口对象。动态代理主要是基于反射特性实现的

其中动态代理的实现方式有JDK实现Cglib框架实现两种方式,二者最大的不同在于JDK实现的代理对象是接口的实现对象,和被代理对象是并列关系;而Cglib实现的代理对象是被代理对象的继承子对象,是继承关系

JDK实现


JDK实现动态代理基于 ProxyInvocationHandler这两个JDK提供的类

获取代理对象

我们通过静态方法 Proxy.newProxyInstance获取一个代理对象,其中

1
public Object newProxyInstance(ClassLoader loader,@NotNull Class<?>[] interfaces,@NotNull InvocationHandler h)
  • loader传入被代理类的类加载器
  • interfaces传入被代理类实现的接口的Class对象,考虑到可能有多个实现接口故传入一个数组
  • h传入实现该接口中方法的handler

实现接口

InvocationHandler接口需要实现以下方法:

1
public Object invoke(Object proxy,Method method,Object[] args) throw Throwable
  • proxy是代理对象
  • method是当前被调用方法的反射对象
  • args是参数列表

举例来说:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Controller ctrl=new ControllerImpl();

InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("aPointCut")){
System.out.println("Here is a pointcut.");
}
//注意这里因为要代理的是Controller的实现类的实例对象ctrl,所以应当传入被代理的实例对象
//JDK实现的反射中,代理对象是独立于被代理对象的另一个**兄弟对象**,因此无法直接调用被代理对象
Object ret=method.invoke(ctrl,args);
return ret;
}
};

//ctrl的代理对象
Controller proxyCtrl=(Controller) Proxy.newProxyInstance(ctrl.getClass().getClassLoader(),ctrl.getClass().getInterfaces(),handler);

Cglib实现


Cglib已经包含在Spring的依赖库内,可以直接调用 org.springframework.cglib.proxy.Enhancer实现

Cglib实现动态代理基于 Enhancer

对于Cglib实现,代理方法除传入InvocationHandler外,也提供了更强大的 MethodInterceptor,此外,由于Cglib是基于继承的,因此也支持被代理对象不实现对应接口

在Spring AOP中,如果检测到

其中MethodInterceptor要求实现以下接口:

1
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  • obj是代理对象
  • method是当前被调用方法的反射对象
  • args是参数列表
  • proxy是当前被调用方法的代理方法
    • 其中可以通过 proxy.invokeSuper方法调用该方法的父类实现

和Proxy不同,Enhancer是一个实例对象。在通过Enhancer获取代理对象前,需要先设置参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Enhancer enhancer=new Enhancer();

//这里传入被代理对象的类的Class对象,Enhancer会自动创建一个继承自该类的子代理类
enhancer.setSuperClass(ControllerImpl.class);

//传入回调函数,这里同Invocation的设置,此外也可以传入MethodInterceptor
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if(method.getName().equals("aPointCut")){
System.out.println("Here is a pointcut.");
}
//Cglib实现的反射中,代理对象是继承于被代理对象的**子对象**,可以直接调用obj来获取被代理对象
Object ret=proxy.invokeSuper(obj,args);
return ret;
}
});

//ctrl的代理对象
Controller proxyCtrl= (Controller) enhancer.create();
Comments