動態代理應用普遍,Spring,Struts等框架不少功能是經過動態代理,或者進一步封裝來實現的。java
常見的動態代理模式實現有Java API提供的動態代理和第三方開源類庫CGLIB動態代理。框架
Java API提供的動態代理是基於類反射實現的,用到的類有:ide
java.lang.reflect.InvocationHandler;測試
java.lang.reflect.Method;this
java.lang.reflect.Proxy;
spa
其實現是經過Proxy類的newProxyInstance()方法產生代理對象。自定義動態代理類須要實現InvocationHandler接口,該接口只有一個invoke()方法。代理
CGLIB是經過生成java 字節碼從而動態的產生代理對象,所以須要字節碼解析處理的依賴asm類庫,字節碼動態生成的代理對象其實是繼承了真實主題類的。這種實現方式須要導入cglib和asm的類庫。下面用到的例子是cglib-2.2.2.jar, asm-3.3.1.jar。cglib使用了MethodInterceptor,其中的方法是intercept(),這是攔截的概念,很容易就想到了Struts2的攔截器。code
比較之下,Java API提供的動態代理須要面向接口,產生代理對象,所以真實主題實現類必須實現了接口才能夠。而CGLIB不須要面向接口,能夠代理簡單類,但因爲動態代理對象是繼承真實主題實現類的,所以要求真實主題實現類不能是final的。orm
下面是實現的例子。對象
首先,爲了看到動態代理能夠根據不一樣類動態產生不一樣代理的效果,咱們新建兩個接口,及其實現類。
package leon.aj.dynproxy.target; public interface Hello { public String sayHello(String name); }
實現類:
package leon.aj.dynproxy.target; public class HelloImpl implements Hello { @Override public String sayHello(String name) { String s = "Hello, "+name; System.out.println(this.getClass().getName()+"->"+s); return s; } }
另外一接口和實現類:
package leon.aj.dynproxy.target; public interface UserDao { public boolean login(String username,String password); }
package leon.aj.dynproxy.target; public class UserDaoImpl implements UserDao { @Override public boolean login(String username, String password) { String user = "("+username+","+password+")"; System.out.println(this.getClass().getName()+"-> processing login:"+user); return true; } }
應用Java API實現的動態代理類:
package leon.aj.dynproxy.java; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JavaDynProxy implements InvocationHandler{ private Object target; public Object getProxyInstance(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 result = null; System.out.println("before target method..."); result = method.invoke(target, args); System.out.println("after target method..."); return result; } }
測試:
package leon.aj.dynproxy.java; import leon.aj.dynproxy.target.Hello; import leon.aj.dynproxy.target.HelloImpl; import leon.aj.dynproxy.target.UserDao; import leon.aj.dynproxy.target.UserDaoImpl; public class TestJavaProxy { public static void main(String[] args) { JavaDynProxy proxy = new JavaDynProxy(); Hello hello = (Hello)proxy.getProxyInstance(new HelloImpl()); String s = hello.sayHello("Leon"); System.out.println(s); UserDao userDao = (UserDao) proxy.getProxyInstance(new UserDaoImpl()); userDao.login("Leon", "1234"); System.out.println(userDao.getClass().getName()); } }
下面是採用cglib實現的例子:
package leon.aj.dynproxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { private Object target; public Object getProxyInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); // call back method return enhancer.create(); // create proxy instance } @Override public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before target method..."); Object result = proxy.invokeSuper(target, args); System.out.println("after target method..."); return result; } }
測試類:
package leon.aj.dynproxy.cglib; import leon.aj.dynproxy.target.Hello; import leon.aj.dynproxy.target.HelloImpl; import leon.aj.dynproxy.target.UserDaoImpl; public class TestCiglib { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Hello hello = (Hello) proxy.getProxyInstance(new HelloImpl()); System.out.println(hello.sayHello("Leon")); UserDaoImpl userDao = (UserDaoImpl) proxy.getProxyInstance(new UserDaoImpl()); userDao.login("Leon", "1234"); System.out.println(userDao.getClass().getSuperclass());//看動態代理實例的父類 } }