java动态代理机制中有两个重要的类和接口InvocationHandler(接口)和Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心;
实现jdk代理的几大步骤
1)通过实现InvocationHandler接口来自定义自己的InvocationHandler;
2)通过Proxy.getProxyClass获得动态代理类;
3)通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class);
4)通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入;
5)通过代理对象调用目标方法;
IHello接口
package com.lanhuigu.spring.proxy.jdk; public interface People { void sayHello(); }
HelloImpl实现类
package com.lanhuigu.spring.proxy.jdk; public class Teacher implements People { @Override public void sayHello() { System.out.println("Hello world!"); }
MyInvocationHandler实现类(实现的是invocatinHandler接口)
说明每一个动态代理类的调用处理程序都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了实现该接口的动态代理类调用处理程序中,当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用
package com.lanhuigu.spring.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { /** 目标对象 */ private Object target; public MyInvocationHandler(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------插入前置通知代码-------------"); // 执行相应的目标方法 Object rs = method.invoke(target,args); System.out.println("------插入后置处理代码-------------"); return rs; }
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { // 1、生成$Proxy0的class文件 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); // 2、获取动态代理类 //.Proxy类就是用来创建一个代理对象的类 //第一个参数表示获取Peopled的类加载器,第二个是真实类 Class proxyClazz = Proxy.getProxyClass(People.class.getClassLoader(),People.class); // 3、获得代理类的构造函数,并传入参数类型InvocationHandler.class Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class); // 4、通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入 // constructor.newInstance后面有说明 IHello iHello1 = (IHello) constructor.newInstance(new MyInvocationHandler(new Teacher())); // 5、利用对象来调用方法 iHello1.sayHello();
第二种: People people = new Teacher(); //代理对象的调用处理程序,我们将要代理的真实对象(people)传入代理对象的调用处理的构造函数中, //最终代理对象的调用处理程序会调用真实对象的方法 InvocationHandler handler = new MyInvocationHandler(people); /** * 通过Proxy类的newProxyInstance方法创建代理对象,我们来看下方法中的参数 * 第一个参数:代理对象 * 第二个参数:接口中的方法 * 第三个参数:关联handler */ People proxy = (People)Proxy.newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler); //System.out.println(proxy.toString()); System.out.println(proxy.work()); }
两种调用方法区别
Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;
Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。
Class.newInstance() 抛出所有由被调用构造函数抛出的异常。
Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;
Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。