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");
}
}