1、动态代理流程图 在运行状态中,需要代理的地方,根据 Subject 和 RealSubject,动态地创建一个 Proxy,用完之后,就会销毁,这样就可以避免了 Proxy 角色的 class 在系统中冗杂的问题了。 动态代理步骤:
- 获取 RealSubject 上的所有接口列表;
- 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
- 根据需要实现的接口信息,在代码中动态创建 该 Proxy 类的字节码;
- 将对应的字节码转换为对应的 class 对象;
- 创建 InvocationHandler 实例 handler,用来处理 Proxy 所有方法调用;
- Proxy 的 class 对象 以创建的 handler 对象为参数,实例化一个 proxy 对象。
从上面可以看出,JDK 动态代理的实现是基于实现接口的方式,使得 Proxy 和 RealSubject 具有相同的功能。
在 Java 的动态代理机制中,有两个重要的类(接口),一个是 InvocationHandler 接口、另一个则是 Proxy 类,这一个类和一个接口是实现我们动态代理所必须用到的。
//备注:invoke在动态代理对象调用方法前,会先进入invoker方法
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
参数说明:
- proxy - 代理的真实对象。
- method - 所要调用真实对象的某个方法的 Method 对象
- args - 所要调用真实对象某个方法时接受的参数
Proxy 类
Proxy 这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
这个方法的作用就是得到一个动态的代理对象。
参数说明:
- loader - 一个 ClassLoader 对象,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载。
- interfaces - 一个 Class<?>
对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了 - 一个 InvocationHandler 对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个
InvocationHandler 对象上
代码如下:
先定义一个接口
package com.example.demo.dynamicProxy;
public interface Subject {
void hello(String str);
String bye();
}
继承它
package com.example.demo.dynamicProxy;
public class RealSubject implements Subject {
@Override
public void hello(String str) {
System.out.println("Hello " + str);
}
@Override
public String bye() {
System.out.println("Goodbye");
return "Over";
}
}
创造动态代理类 实现动态代理逻辑
package com.example.demo.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class InvocationHandlerDemo implements InvocationHandler {
private Object subject;
public InvocationHandlerDemo(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable {
System.out.println("Before method");
System.out.println("Call Method: " + method);
Object obj = method.invoke(subject, args);
System.out.println("After method");
System.out.println();
return obj;
}
}
客户端请求
package com.example.demo.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new InvocationHandlerDemo(realSubject);
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println("111:"+subject.getClass().getName());
System.out.println("---------------------------------");
subject.hello("World");
String result = subject.bye();
System.out.println("Result is: " + result);
}
}
结果:
JDK 动态代理小结
代理类与委托类实现同一接口,主要是通过代理类实现 InvocationHandler 并重写 invoke 方法来进行动态代理的,在 invoke 方法中将对方法进行处理。
JDK 动态代理特点:
优点:相对于静态代理模式,不需要硬编码接口,代码复用率高。
缺点:强制要求代理类实现 InvocationHandler 接口。
|