先总结一下上篇文章使用JDK动态代理实现AOP的步骤:
- 定义一个服务类接口
- 进行接口的实现
- 编写InvocationHandler的实现类用于封装目标对象和目标类的方法
- 声明接口类型的服务实现类对象,使用该对象创建我们的InvocationHandler实现类
- 使用Proxy.newProxyInstance方法获得目标对象的封装对象
当然我们也总结了JDK动态代理的一些缺点,我们可以对比Cglib看看哪个更加强大、各有什么优缺点、什么条件下选择哪种动态代理实现方式。JDK动态代理的缺点有:
- 必须要存在服务类接口。如论你的业务逻辑复杂与否都必须提供一个服务接口,哪怕是标志接口
- 代理对象的创建效率跟正常的new操作没有区别,所以说代理对象的创建没有额外的性能损耗但是使用JDK动态代理创建的代理对象是在运行时动态的更改类的信息,所以使用时效率受到了很大的影响
- 创建代理对象的过程有点繁琐(上面总结的5步)
下面来看Cglib动态代理:Cglib动态代理使用底层的字节码技术,为每个代理对象生成一个子类,在子类中拦截所有父类的方法,织入横切代码。
这里来看一个接口:MethodInterceptor,属于cglib-nodep-2.1_3.jar。该接口只有一个方法用于拦截父类的方法:intercept(Object obj,Mathod method,Object[] args,MethodProxy proxy),参数中的各个对象分别是目标对象,目标方法,目标方法的参数,代理方法。下面再看看上一篇文章中使用JDK实现动态代理的代码怎样使用Cglib怎样进行实现。
代理对象:
class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clz){
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName()+"()");
Object result = method.invoke(obj, args);
PerformanceMonitor.end();
return result;
}
}
该代理对象提供了一个工厂方法用于获得代理对象,封装了代理对象的创建过程。再看看测试代码:
CglibProxy cglibInterceptor = (CglibProxy) new CglibProxy().getProxy(ForumServiceImpl.class);
forumService.removeForum(1);
forumService.removeTopic(200);
这样以来,创建代理对象的方法就被浓缩到了一行,是不是比使用JDK动态代理更加明了?当然,使用GDK动态代理创建代理对象的方法我们也可以进一步优化。
最后我们再来对比一下GDK动态代理和Cglib两者实现AOP的各自优缺点:
- 使用Cglib实现动态代理时,是使用字节码技术创建一个目标类的子类,然后使用该子类的实例作为代理对象进行业务操作。所以,创建代理对象的过程效率降低了【使用GDK动态代理创建代理对象效率的八分之一】,因为要先创建目标类的子类。但是执行业务操作时效率是Cglib的10倍。
- 以用GDK动态代理时创建代理对象的效率相比Cglib很高(8倍),但是它创建出来的对象在进行业务操作时动态的进行Class信息的更改,所以使用效率低,是Cglib的十分之一。所以说:如果一个业务代理对象是单例的,完全应该使用Cglib进行实现。
- 使用Cglib进行动态代理,是创建一个子类继承至目标类,所以不需要像GDK动态代理那样提供一个接口,这样节约了类的个数。
作为代理的入门课程,AOP的前两节基础课程就讲到这里,下节课开始正式写Spring的AOP!