动态代理是Spring Aop的基础,分为基于JDK的动态代理(接口实现)和基于CGLIB的动态代理(继承实现)。
声明一个被代理的类:
package com.maheng.proxy.jdk; public interface IUser { public void save(String name); }
package com.maheng.proxy.jdk; public class User implements IUser{ @Override public void save(String name) { System.out.println("save " + name); } }
使用装饰模式来实现静态代理:
package com.maheng.proxy.jdk; public class StaticProxy implements IUser{ private IUser target; public StaticProxy(IUser target){ this.target = target; } @Override public void save(String name) { System.out.println("begin save"); target.save(name); System.out.println("end save"); } }
基于JDK的动态代理:
package com.maheng.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * 基于jdk的动态代理 * @autor maheng * @date 2016.4.25 * */ public class DynamicProxy implements InvocationHandler{ private Object target; public Object proxy(Object target){ this.target = target; // 动态创建一个代理对象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 调用代理对象的任何方法,都会执行该方法 * 相当于拦截代理对象的方法 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object resout = null; System.out.println(proxy.getClass()); System.out.println("begin"); resout = method.invoke(target, args); System.out.println("end"); return resout; } }
测试用例:
package com.maheng.proxy.jdk; public class Test { /** * @param args */ public static void main(String[] args) { StaticProxy staticProxy = new StaticProxy(new User()); staticProxy.save("maheng"); System.out.println(staticProxy.getClass()); System.out.println("============="); DynamicProxy dynamicProxy = new DynamicProxy(); IUser user = (IUser)dynamicProxy.proxy(new User()); user.save("yuanmeng"); System.out.println(user.getClass()); } }
基于cglib的动态代理:
package com.maheng.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.InvocationHandler; /* * 基于cglib的动态代理 * @autor maheng * @date 2016.4.25 * */ public class DynamicProxy implements InvocationHandler{ private Object target; public Object proxy(Object target){ this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(target.getClass().getClassLoader()); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } /** * 调用代理对象的任何方法,都会执行该方法 * 相当于拦截代理对象的方法 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object resout = null; System.out.println(proxy.getClass()); System.out.println("begin"); System.out.println(target.getClass()); resout = method.invoke(target, args); System.out.println("end"); return resout; } }
测试用例:
package com.maheng.proxy.cglib; import com.maheng.proxy.jdk.IUser; import com.maheng.proxy.jdk.User; public class Test { /** * @param args */ public static void main(String[] args) { DynamicProxy dynamicProxy = new DynamicProxy(); IUser user = (User)dynamicProxy.proxy(new User()); System.out.println(user.getClass()); user.save("maheng"); } }
在使用自动代理时, 在<aop:aspectj-autoproxy proxy-target-class="false"/>标签中设置 proxy-target-class="fasle/true" ,false采用基于jdk的动态代理,true采用基于cglib的动态代理。
在使用基于jdk的动态代理时,如果出现java.lang.ClassCastException,将需要代理的类用接口实现就可以避免这个问题,原因是:产生的代理类$Proxy0和被代理的类之间没有直接关系,强制类型转换自然会失败,先声明接口那么产生的代理类$Proxy0和被代理的类实现了相同的接口,就可以使得$Proxy0类型转换为定义的接口类型来避免这个问题。而基于cglib的动态代理中产生的代理类*$$EnhancerByCGLIB$$*继承于被代理的类,自然就不会出现类型转换失败的异常了。