原文链接

  • 静态代理
  • 动态代理
    • JDK动态代理
    • cglib动态代理
    • jdk动态代理和cglib的比较

静态代理

静态代理相对来说比较简单,无非就是聚合+多态:

参考

动态代理

通过使用代理,我们可以在被代理的类的方法的前后添加一些处理方法,例如事务,日志等。这样就达到了类似AOP的效果,而JDK中提供的动态代理,就是实现aop的绝好底层技术。

JDK动态代理

JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。

Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

Java笔记 – 反射 动态代理

CGLib动态代理

还有一个叫CGLib的动态代理,CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。

首先是两个测试类:

1
2
3
4
5
6
7
8
9
interface Animal{
void sound();
}
class Dog implements Animal{
public void sound(){
System.out.println("wong~");
}
}

接下来演示CGLib的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
// 设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
// 通过字节码技术动态创建子类实例
return enhancer.create();
}
// 拦截父类所有方法的调用
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("begin...");
// 通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("end...");
return null;
}
public static void main(String[] args){
CglibProxy proxy = new CglibProxy();
Animal dog = (Animal)proxy.getProxy(Dog.class);
dog.sound();
}
}

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。

JDK动态代理和CGLib的比较

CGLib所创建的动态代理对象的性能比JDK所创建的代理对象性能高不少,大概10倍,但CGLib在创建代理对象时所花费的时间却比JDK动态代理多大概8倍,所以对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建新的实例,所以比较适合CGLib动态代理技术,反之则适用于JDK动态代理技术。另外,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行处理。所以,大家需要根据实际的情况选择使用什么样的代理了。

同样的,Spring的AOP编程中相关的ProxyFactory代理工厂内部就是使用JDK动态代理或CGLib动态代理的,通过动态代理,将增强(advice)应用到目标类中。