Spring_AOP2<JDK动态代理&CGLIB动态代理>
昨天那篇文章肤浅地介绍了Spring的IOC和AOP,今天继续学习AOP,那么在Spring中的AOP是动态代理实现的,生成代理的的机制有两种,一种是实现接口的形式,JDK动态代理就是用的这种方式,还有一种是生成子类的方式,如CGLIB。
用jdk动态代理,被代理的类必须实现接口,CGLIB动态代理要求被代理目标不能是final修饰的类。
先说说JDK动态代理,用到了JDK中的Proxy和InvocationHandler
菜鸟开始写代码了:
第一种方式是实现InvocationHandler接口,重写接口中唯一的invoke方法
比如所要在UserJDKProxyDaoImpl的executeAdd方法前后加入一个逻辑,这里用一句话
UserJDKProxyDaoImpl:
/** * 注意要实现接口 * @author PingCX * */public class UserJDKProxyDaoImpl implements UserDao { public void executeAdd() { System.out.println("hurry upto add time is limited......"); }}那代理类的写法,详细解释在代码注释中:
/** * 一个自定义动态代理类,实现了InvocationHandler * @author PingCX * */public class JDKProxy implements InvocationHandler {//被代理目标,动态指定private Object target;public void setTarget(Object target) {this.target = target;}/** * 这个方法时自定义的,用于生成代理类, * 也可以在测试时将里面的生成代理对象的代码单独写这么设计更符合面向对象 * 让代理自身负责代理的创建 * @param targetObject * @return 生成的代理 */public Object createProxy() {/* * 1.target.getClass().getClassLoader(),一个别代理目标的类加载器 * 2.target.getClass().getInterfaces(),是被代理目标实现的接口,所以要求实现接口, * 可以理解为代理根据这个接口生成对应的方法 * 3.this 代理自身,用于在调用被代理目标是能够识别代理并隐式调用自身的invoke作为第一个参数方法, * 这个设计很巧妙 */return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);}/** * 代理执行方法时隐式调用的方法,一定会被调用的方法,是InvocationHandler接口中的唯一方法 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("ready go......");//被代理目标方法执行前的逻辑Object obj = method.invoke(target, args);//执行被代理目标的方法System.out.println("everything is over......");//被代理目标方法执行后的逻辑return obj;}}个中原理,就是这么一回事,战略上藐视它,其实就是这么着,当然深入研究,就要去看源码了,内部涉及到的东西还不少,这里主要是想说明Spring的AOP代理原理,所以菜鸟也说不上更多的了。
改进一下上面的代码,重构一下,将代理用内部类实现:
/** * JDK代理,要求被代理对象的类实现接口,用内部类的方式实现更有利于测试,且代码易读 * @author Administrator * */public class JDKProxy2 {private Object target;public JDKProxy2(Object target) {this.target = target;}/** 第一个参数设置代码使用的类装载器,一般采用跟目标类相同的类装载器* 第二个参数设置代理类实现的接口* 第三个参数设置回调对象,当代理对象的方法被调用时,会委派给该参数指定对象的invoke方法*/public Object createProxy() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new MyInvocationHandler());}class MyInvocationHandler implements InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("ready go......");Object obj = method.invoke(target, args);System.out.println("everything is over......");return obj;}}} 原理相似,调用一样的调用,只是设计上有点不同。
JDK代理是实现接口的方式,其实在Spring的AOP应中,这种方式是常用的,还有一种是生成子类,简单说说CGLIB的实现,用到了第三方jar包中的MethodProxy,MethodInterceptor,可以理解为方法的拦截器,就是将制定的方法拦截下来,再进行业务逻辑的加入:
/** * CGLIBProxy是动态代理目标对象所属的类的一个子类,所以要求该类可以被继承,不能使final类 * @author Administrator * */public class CGLIBProxy2{ private Object target; public CGLIBProxy2(Object target) { this.target = target; } /** * 获取代理对象,我咋觉得这个是把JDK中的方法的三个参数分解了 * @return */ public Object createProxy(){ Enhancer enhancer = new Enhancer();//该类用于生成代理对象 enhancer.setSuperclass(this.target.getClass());//设置父类 enhancer.setCallback(new MyMethodInterceptor());//设置回调对象为本身 return enhancer.create();//create()方法产生对象 } class MyMethodInterceptor implements MethodInterceptor { /** *执行代理 */ public Object intercept(Object arg0, Method arg1,Object[] arg2, MethodProxy arg3) throws Throwable { System.out.println("haha I am cglibproxy welcome to useme to develop......"); Object returnValue = arg1.invoke(target, arg2); System.out.println("thank you for your using,hope youcome back later......"); return returnValue; } }}两种代理机制的代码实现了,继续学习Spring...