动态代理使用不在累述。InvocationHandler.invoke的第一个参数proxy值是newProxyInstance返回的动态代理类的实例,不是被代理的实例。
动态代理类Proxy是结合java底层实现的,通过纯粹的java代码实现比较困难。
需要java动态生成类的支持。
要创建一个可以代理任何接口的类:
1.必须要知道要被代理的接口列表;
2.要有一个可以加载这个代理类的ClassLoader;
3.为了能够在调用被代理实例接口时能够动态的添加需要的处理,需要一个接口回调,并在回调中采用反射的形式调用实际的实例方法。
实现过程:以下Proxy是实现动态代理的过程
public interface Subject{
public void rent();
public void hello(String str);
}
public 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);
}
}
public class DynamicProxyHandler implements InvocationHandler {
// 被代理对象
private Object subject;
public DynamicProxy(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("Method:" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent house");
return null;
}
}
public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new DynamicProxyHandler(realSubject);
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
}
subject.getClass().getName()打印的值是:$Proxy0
image.png
猜测大概的$Proxy0类如下(可以通过反射查看其中的一部分实际内容):
// 类的包名应该是和Proxy在同一个包下
public class Proxy0 implements Subject {
private InvocationHandler handler;
public Proxy0(InvocationHandler handler) {
this.handler = handler;
}
public void rent() {
Thread.currentThread().getStackTrace()[2].getMethodName();
// 通过反射获取当前函数名称和参数列表,传给invoke
Proxy.invoke(this, method, args);
}
public void hello(String str) {
Proxy.invoke(this, method, args);
}
}
InvocationHandler的实现可以多种多样,根据不同需求进行不同实现。
网友评论