动态代理模式
动态代理模式不再像静态代理模式那样,为没一个真实对象去增加一个代理类,而是利用java反射去动态生成一个代理类。动态代理跟静态代理角色是一样的。
动态代理分为两大类
- 基于接口的动态代理—jdk动态代理【本博客以jdk动态代理为例】
- 基于类的动态代理—cglib动态代理
Proxy
Proxy提供了创建动态代理类的静态方法
public static Object newProxyInstance(
ClassLoader loader,//类加载器 来定义这个返回的代理类的类型
类<?>[] interfaces,//这个真实对象实现的接口
InvocationHandler h//调用处理程序
)
InvocationHandler
调用处理程序。这是一个接口。每个代理实例都有一个关联的处理程序(代理类),当在代理实例上调用该方法时,方法调用将被编码并分发到其他调用处理程序的invoke方法。
invoke(Object proxy, Method method, Object[] args) throws Throwable
- proxy:调用该方法的代理实例
- method:代理的这个类的一个方法或者这个类实现的接口
- args:方法中的参数
创建一个普通java项目
真实对象
package com;
//真实角色:房东,需要实现抽象角色这个接口
public class Master implements Rent {
public void rent() {
System.out.println("房东出租房子!");
}
}
接口
package com;
//抽象角色,租房子(一般是接口或者抽象类)
public interface Rent {
//出租房屋
public void rent();
}
生成代理类的处理程序
这个类可以当成一个工具类
package com;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//调用程序处理角色
//等会可以用这个类来自动生成代理类,这不是代理类,只是一个真实对象的处理程序
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的真实对象
private Object object;
public void setObject(Object object) {
this.object = object;
}
/**
* 得到生成的代理对象
* newProxyInstance的三个参数
* this.getClass().getClassLoader()。类加载器,为了加载到类在哪个位置
* rent.getClass().getInterfaces()。获取真实角色的接口
* this:即实现了InvocationHandler这个接口的类,
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
}
/**
* 处理真实对象,并返回结果
* @param proxy
* @param method 这是一个反射对象,主要是去执行method.invoke()
* @param args 参数集,这些参数丢入invoke里面去执行
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 动态代理的本质,就是使用反射机制去实现
* 还可以做一些其他事情
*/
log(method.getName());
Object invoke = method.invoke(object, args);
return invoke;
}
public void log(String msg) {
System.out.println("执行了" + msg + "方法");
}
}
客户端
package com;
//客户
public class Client {
public static void main(String[] args) {
//真实角色
Master master = new Master();
//获取生成代理类的处理程序的对象
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//通过调用处理角色来处理我们要调用的接口对象
proxyInvocationHandler.setObject(master);
Rent proxy = (Rent) proxyInvocationHandler.getProxy();
proxy.rent();
}
}
执行了rent方法
房东出租房子!
Process finished with exit code 0
动态代理的好处
-
可以使真实角色的操作更加纯粹,不用去关注一些公共业务
-
公共的业务交给代理角色,实现了业务的分工
-
公共业务发生扩展的时候,方便集中管理
-
一个动态代理类代理的是一个接口,一般就是对应的一类业务
-
一个动态代理类的处理程序,可以生成多个类的代理角色,只要真实角色实现了相同的接口