通过JDK实现动态代理,有代理需求的类(这里称之为实现类)必须要实现接口。动态代理可以将逻辑切片,通过代理类(proxy)代实现类实现逻辑,期间还可以进行一些其他的操作。JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一 起。关于动态这块儿一直比较迷惑,傻傻分不清楚,今天又有了新的理解,下面通过一个简单的例子来说明:
先叙述下事务逻辑:一个人(people对象)通过交通工具(Transportation处理类)去了外国(日本、英国)
1、将去英国和日本这两件事当做两个接口,由人来实现
package com.impetention.lei; public interface Japan { public void goJapan(); } -------------------------------------------- package com.impetention.lei; public interface England { public void goEngland(); } ------------------------------------------------- package com.impetention.lei; //实现类 public class People implements England,Japan { @Override public void goEngland() { // TODO Auto-generated method stub System.out.println("I am in England !"); } @Override public void goJapan() { // TODO Auto-generated method stub System.out.println("I am in Japan !"); } }
2、现在介绍一下InvocationHandler
,它是代理类的调用处理程序 实现的接口。每个代理类都具有一个关联的调用处理程序,在实例化代理类时会添加进去一个InvocationHandler类型的处理类(完成事务逻辑的主题)。
如:
package com.invocation; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import com.impetention.lei.People; //人通过交通工具(代理)去国外 public class Transportation implements InvocationHandler { //一个叫zhang的人 private Object zhang = null; public Transportation(Object zhang) { this.zhang = zhang; } @Override public Object invoke(Object proxy, Method method, Object[] args) { // TODO Auto-generated method stub System.out.println("可以执行一些其他方法....."); //记录执行结果 Object result = null; zhang = new People(); //在zhang对象上执行method方法,并将结果返回 try { result = method.invoke(zhang, args); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("---------------------"); return result; } }
注意里面红色的proxy,它就是代理类实例。这里有必要对invoke(Object proxy, Method method, Object[] args) 做出一些解释,动态代理类proxy0调用goEngland()方法时会调用它自己的goEngland()方法, 而它自己的goEngland()方法里面调用的是其绑定对象InvocationHandler对象的invoke()方法, 也就是Transportation的invoke方法。invoke(Object proxy, Method m, Object[] args)种的proxy实际上就是动态代理类proxy, 如果你将其强转成England然后调用它的goEngland()方法,它又会触发代理类的goEngland()方法,代理类又调用InvocationHandler(transportation)的invoke()方法,这样就会死循环。
3、代理实现:
package com.main; import java.lang.reflect.Proxy; import com.impetention.lei.England; import com.impetention.lei.Japan; import com.impetention.lei.People; import com.invocation.Transportation; public class Peopletest { public static void main(String[] args) { //准备用动态代理实现,一个叫li的人通过交通工具到了英国 England li = new People(); //实例化transportation对象 Transportation t1 = new Transportation(li); //通过li.getClass().getClassLoader()实现类的类加载器和li.getClass().getInterfaces()实现类实现的所有接口作为参数调用
//Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)的方法返回代理类的java.lang.Class对象获得了一个proxy代理类,
//必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类方法执行前后做额外工作的类transpotation。将代理类强转成England类型
England proxy = (England) Proxy.newProxyInstance(li.getClass().getClassLoader(), li.getClass().getInterfaces(), t1); proxy.goEngland(); //准备用动态代理实现,一个叫li的人通过交通工具到了英国 Japan lei = new People(); //实例化transportation对象 Transportation t2 = new Transportation(lei); //通过li.getClass().getClassLoader()和li.getClass().getInterfaces()获得了一个 //(java.lang.class)proxy代理类,并以tt为参数对其进行实例化,强转成people类型 Japan proxy1 = (Japan) Proxy.newProxyInstance(li.getClass().getClassLoader(), li.getClass().getInterfaces(), t2); proxy1.goJapan(); } }
小结:过程是这样的,people执行goEngland()方法不直接执行,而是通过代理类proxy,proxy执行它自己的goEngland(),会触发Transportation调用invoke(),然后
method.invoke(zhang, args);zhang会调用它的method,即goEngland(),最后将结果返回。