动态代理
代理模式
概念:为其它对象提供一种代理以控制对这个对象的访问
本质:触发被代理安排;但是执行者还是被代理本身执行(包括动态代理)
类图
-
Subject抽象主题角色
可以是抽象类也可以是接口
-
RealSubject具体主题角色
委托角色、被代理角色(业务逻辑的具体执行者)
-
Proxy代理主题角色
委托类、代理类;它负责对真实角色的应用,把所有抽象主题类定义的方法委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理的工作。
抽象主题类
public interface Subject { void method(); }
真实主题类
public class RealSubject implements Subject { //实现方法 @Override public void method() { //具体业务处理 } }
代理类
public class Proxy implements Subject { //要代理的对象 private Subject subject; //构造函数中;传入要代理的对象 public Proxy(Subject realSubject) { this.subject = realSubject; } //实现接口中定义的方法 @Override public void method() { //预处理 this.before(); //代理的对象执行业务逻辑 this.subject.method(); //善后处理 this.after(); } private void before() { //预处理 } private void after() { //善后处理 } }
为什么使用代理
-
职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其它非本职的工作
高扩展
补充功能
动态代理
概念
在实现阶段不关心代理谁,而在运行阶段才指定代理哪个对象
为什么会产生动态代理
- 静态代理代理类和被代理类实现了相同的接口,导致代码重复,可扩展性差(被代理类增加方法,代理类也要实现这个方法)
- 静态代理代理类只服务于一种类型的代理
动态代理分类
动态代理主要分为JDK动态代理和cglib动态代理两大类
JDK动态代理
必要条件:必须有被代理类的接口
UML图
抽象被代理角色
public interface Subject {
//业务操作
public void doSomething(String str);
}
真实被代理角色
public class RealSubject implements Subject{
//业务操作
@Override
public void doSomething(String str) {
System.out.println("do something------> " + str);
}
}
动态代理Handler
public class MyInvocationHandler implements InvocationHandler{
//被代理的对象
private Object target;
//通过构造函数传入被代理对象
public MyInvocationHandler(Object target) {
this.target = target;
}
//参数1:proxy 动态代理对象
//参数2:method 正在执行的方法
//参数3:args 调用目标方法时传入的实参
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行被代理的方法
return method.invoke(this.target, args);
}
测试类1
public class Client1 {
public static void main(String[] args) {
//定义被代理类
Subject realSubject = new RealSubject();
//定义一个handler
InvocationHandler handler = new MyInvocationHandler(realSubject);
//动态代理类
//第一个参数:用于定义代理类的类加载器;传入被代理类接口的类加载器(动态)
//注意 第一个参数加载器 不是handler的加载器,handler不是代理类
//第二个参数:被代理类的接口
//第三个参数:InvocationHandler,用来处理方法的调用
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
//代理的行为
proxy.doSomething("Finish");
}
}
输出:
do something------> Finish
测试类2
public class Client2 {
public static void main(String[] args)
throws Exception {
//定义被代理类
Subject realSubject = new RealSubject();
//定义一个handler
InvocationHandler handler = new MyInvocationHandler(realSubject);
//使用Proxy生成一个动态代理类ProxyClass
Class> proxyClass = Proxy.getProxyClass(Subject.class.getClassLoader(),
new Class[] {Subject.class});
//获取proxyClass类中一个invocationHandler参数的构造器
Constructor> constructor =
proxyClass.getConstructor(new Class[] {InvocationHandler.class});
//调用constructor 的newInstance方法创建动态实例
Subject proxy = (Subject) constructor.newInstance(new Object[] {handler});
//代理的行为
proxy.doSomething("Finish");
}
}
输出:
do something------> Finish
JDK动态代理分析
Proxy
提供用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。
Proxy提供了如下两个方法来创建动态代理类和动态代理实例
public static Class> getProxyClass(ClassLoader loader,
Class>... interfaces)
创建一个动态代理类所对应的class对象,该代理类将实现interfaces所指定的所有接口。如以上测试类2
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
直接创建一个动态代理对象,该代理对象实现了interfaces指定的系列接口,执行代理对象的每个方法时都会被替换执行InvocationHandler对象的invoke方法
动态代理类由输出到硬盘
public class CreateProxyClass {
public static void main(String[] args) {
// 使用Proxy生成一个动态代理类ProxyClass
Class> proxyClass = Proxy.getProxyClass(
Subject.class.getClassLoader(),
new Class[] { Subject.class });
//将动态生成的代理类生成字节码;并输出到D盘Proxy.class
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy",
proxyClass.getInterfaces());
String path = "D://Proxy.class";
try (FileOutputStream out = new FileOutputStream(path);){
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
查看 D://Proxy.class
import com.dwb.design.proxy.demo1.*;
import java.lang.reflect.*;
public final class $Proxy extends Proxy implements Subject
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy(final InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(final Object o) {
try {
return (boolean)super.h.invoke(this, $Proxy.m1, new Object[] { o });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, $Proxy.m2, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
//重点查看该方法:我们写的业务方法;
public final void doSomething(final String s) {
try {
//对应到 InvocationHandler的三个参数;为什么第一个为动态代理类
//解释了,调用方法最后都会调用重写的InvocationHandler 的invoke方法
super.h.invoke(this, $Proxy.m3, new Object[] { s });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final int hashCode() {
try {
return (int)super.h.invoke(this, $Proxy.m0, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
static {
try {
$Proxy.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
$Proxy.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class>[])new Class[0]);
$Proxy.m3 = Class.forName("com.dwb.design.proxy.demo1.Subject").getMethod("doSomething", Class.forName("java.lang.String"));
$Proxy.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class>[])new Class[0]);
}
catch (NoSuchMethodException ex) {
throw new NoSuchMethodError(ex.getMessage());
}
catch (ClassNotFoundException ex2) {
throw new NoClassDefFoundError(ex2.getMessage());
}
}
}
运行时动态代理UML
说明:蓝色部分为运行时生成的代理对象$Proxy; 该代理类继承了Proxy、实现了被代理接口、组合了InvocationHandler;
代理对象执行过程:
- 先调用自身实现的被代理接口方法
- 调用组合的invocation对象,invoke方法(参数1:代理对象,参数2:被代理接口方法,参数3:方法参数)
- 反射执行被代理方法;invocation对象中invoke方法体内method.invoke(this.target, args)