Spring AOP(2):Cglib动态代理

先总结一下上篇文章使用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!

你可能感兴趣的:(spring,AOP,jdk)