java使用反射生成JDK动态代理
一、基本简介 在java的java.lang.reflect包下提供了一个Proxy类和InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象。
Proxy类提供了两个方法:
- static Class< ? > getProxyClass( ClassLoader loader,Class< ? > … interfaces) : 创建一个动态代理类所对应的Class对象,该代理类将实现interfaces所指定的多个接口。 第一个参数指定生成动态代理类的类加载器。
- static Object newProxyInstance( ClassLoader loader,Class< ? >[] interfaces,InvocationHandler h): 直接创建一个动态代理对象,该代理对象的实现类实现了Interfaces指定的系列接口,执行代理对象的每个方法都会被替换成InvocationHandler对象的invoke方法。
实际上,即使采用第一种方法生成动态代理类之后,如果程序需要通过该代理类来创建代理对象,还是需要传入一个InvocationHandler实例。
代码示例:
try { //创建一个InvocationHandler对象 InvocationHandler invocationHandler = new MyInvocationHandler(); //使用Proxy生成一个动态代理类proxyClass Class proxyClass= Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class); //获取一个proxyClass类带InvocationHandler参数的构造器 Constructor constructor = proxyClass.getConstructor(InvocationHandler.class); //调用constructor的newInstance方法生成动态代理实例 Foo foo = (Foo) constructor.newInstance(invocationHandler); } catch (Exception e) { e.printStackTrace(); }
以上的代码可以简化为下面的代码
InvocationHandler invocationHandler = new MyInvocationHandler(); Foo foo= (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},invocationHandler);
二、实践操作
public interface Person { void sleep(); } public class Man implements Person { @Override public void sleep() { System.out.println("开始睡觉了"); } } public class LogUtil { public void filter1(){ System.out.println("在代理对象的方法执行之前,进行拦截做点什么"); } public void filter2(){ System.out.println("在代理对象的方法执行之后,进行拦截做点什么"); } }
生成代理对象
public class MyProxyFactory { public static Object getProxy(Object target){ MyInvocationHandler handler = new MyInvocationHandler(); handler.setTarget(target); return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler); } }
public class MyInvocationHandler implements InvocationHandler { //需要被代理的对象 private Object target; public void setTarget(Object target){ this.target=target; } //1.proxy代表动态代理的对象 //2.method代表正在执行的方法 //3.args代表调用目标方法时传入的实参 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { LogUtil log = new LogUtil(); log.filter1(); //通过反射执行动态代理对象的所有方法 Object obj=method.invoke(target,args); log.filter2(); return obj; } }
public static void main(String[] args){ Person target = new Man(); Person man= (Person) MyProxyFactory.getProxy(target); man.sleep(); }
运行结果:
三、总结 一般普通编程无需用到动态代理,但在编写框架或底层代码时,它的作用就非常大了。还有就是使用动态代理可以非常灵活的实现解耦。
参考《疯狂java讲义》