JDK自从1.3版本开始,就引入了动态代理,并且经常被用来动态地创建代理,原理之前我已经讲过。JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?现在我们可以使用CGLIB包。
PS:需要引入com.springsource.net.sf.cglib-2.2.0.jar包。
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如:Spring AOP和dynaop,为他们提供方法的interception(拦截); 它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 (CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。)
使用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 | public class CGLIBProxy implements MethodInterceptor { private Object targetObject;//代理的目标对象 public Object createProxyInstance(Object targetObject){ this.targetObject = targetObject; Enhancer enhancer = new Enhancer();//该类用于生成代理对象 enhancer.setSuperclass(this.targetObject.getClass());//设置父类 enhancer.setCallback(this);//设置回调用对象为本身 return enhancer.create(); } public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable { return methodProxy.invoke(this.targetObject, args); } } |
第一个参数是代理对像,第二和第三个参数分别是拦截的方法和方法的参数。通过使用java.lang.reflect.Method对象的一般反射调用或者使用net.sf.cglib.proxy.MethodProxy对象调用都可以完成对原方法的调用,但是通常net.sf.cglib.proxy.MethodProxy对象被首选使用,因为它更快。
PS:net.sf.cglib.proxy.MethodProxy应该是cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升。
示例:
Service类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package net.zmcheng.service; public class PersonService { private String name; public PersonService(){ super(); } public PersonService(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void save(){ System.out.println("我是save方法"); } } |
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | package net.zmcheng.aop; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import net.zmcheng.service.PersonService; public class CglibProxyFactory implements MethodInterceptor{ public Object targetObject; public Object createProxyIntance(Object targetObject){ this.targetObject = targetObject; Enhancer enhancer = new Enhancer();//该类用于生成代理对象 enhancer.setSuperclass(this.targetObject.getClass());//设置父类 enhancer.setCallback(this);//设置回调用对象为本身 return enhancer.create();//创建代理对象 } //MethodInterceptor接口类似于jdk中的java.lang.reflect.InvocationHandler接口 // MethodInterceptor中的intercept方法同java.lang.reflect.InvocationHandler接口中的 invoke方法类似 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy){ //环绕通知 PersonService bean = (PersonService)this.targetObject; Object result = null; if(bean.getName()!=null){ //....advice()--->前置通知 try { result = method.invoke(targetObject, args); //..afteradvice()--->后置通知 } catch (Exception e) { //....exceptionadvice()--->例外通知 e.printStackTrace(); }finally{ //finallyadvice();----->最终通知 } } return result; } } |
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package net.zmcheng.test; import org.junit.BeforeClass; import org.junit.Test; import net.zmcheng.aop.CglibProxyFactory; import net.zmcheng.service.PersonService; public class aopTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void test() { CglibProxyFactory factory = new CglibProxyFactory (); PersonService service = (PersonService)factory.createProxyIntance(new PersonService("zmc")); service.save(); } } |
输出结果:我是save方法
AOP中的概念:
Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面横切性关注点的抽象.
joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)
Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.
Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.