import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理 */ public interface Subject { public void rent(); public void hello(String str); } class RealSubject implements Subject { @Override public void rent() { System.out.println("I want to rent my house"); } @Override public void hello(String str) { System.out.println("hello: " + str); } } class DynamicProxy implements InvocationHandler { private Object subject; //代理的真实对象 /** * 构造方法,给我们要代理的真实对象赋初值 * @param subject */ public DynamicProxy(Object subject) { this.subject = subject; } /** * * @param proxy 动态代理类的引用,通常情况下不需要它。但可以使用getClass()方法,得到proxy的Class类从而取得实例的类信息, * 如方法列表,annotation等。 * @param method 方法对象的引用,代表动态代理类调用的方法。从中可得到方法名,参数,返回类型等等 * @param args 对象数组,代表被调用方法的参数。注意基本类型(int, long)会被装箱成对象类型(Integer,Long) * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("before rent house"); System.out.println("Method: " + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法进行调用 method.invoke(subject, args); // 在代理真实对象后也可以添加一些自己的操作 System.out.println("after rent house"); return null; } } class Client { public static void main(String[] args) { // 我们要代理的真实对象 Subject realSubject = new RealSubject(); //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 InvocationHandler handler = new DynamicProxy(realSubject); /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数:handler.getClass().getClassLoader(),我们这里使用handler这个类的ClassLoader对象 * 来加载我们的代理对象 * 第二个参数:realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实现的接口, * 表示我们要代理的是该真实对象,这里我就能调用这组接口中的方法了 * 第三个参数handler,我们这里将这个代理对象关联到了上方的InvocationHandler这个对象上 * * Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader() * , realSubject.getClass().getInterfaces(), handler); * 1. 为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上, * 我们给这个代理对象提供了一组什么接口 ,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以 * 将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。 * 通过Proxy.newProxyInstance 创建的代理对象是在jvm运行是动态生成的一个对象,它并不是我们的InbacationHandler类型, * 二是在运行时动态生成的一个对象,并且命名方式都是这样的形式(com.sun.proxy.$Proxy0),以$开头,proxy为中,最后一个数字表示对象的标号。 */ Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader() , realSubject.getClass().getInterfaces(), handler); System.out.println(subject.getClass().getName()); subject.rent(); subject.hello("world"); } }