目 录
前言
代理模式有时也被称作委托模式,是一个比较常用/基本的设计模式。代理类不仅会解耦方法的具体实现和方法调用者,而且会对目标方法进行增强。代理模式主要有三类角色:抽象主题角色(ISubject)、委托类角色(被代理角色,RealSubject)和代理类角色(Proxy)。三者之间的关系如下图:
代理模式实践
代理模式实现方式有两类:一类是静态代理(普通代理),代理类在程序运行前就已经存在;另一类是动态代理,代理类在程序运行时创建。代理模式要求客户端只能访问代理角色,不能访问真实角色。
1. 前置代码准备
1.1 domain
/**
* 车辆属性
*/
public class Car implements Serializable {
//编号
private Long id;
//外观颜色
private String shellColor;
//轮子厂商
private String wheelManufacturer;
//车辆类型
private String type;
//价格
private BigDecimal price;
public Car() {}
public Car(Long id, String shellColor, String wheelManufacturer, String type, BigDecimal price) {
this.id = id;
this.shellColor = shellColor;
this.wheelManufacturer = wheelManufacturer;
this.type = type;
this.price = price;
}
//get、set方法
1.2 接口(interface)
public interface CarFactoryService {
/**
* 描述:制造车辆
* @return
*/
Car produceCar();
}
1.3 被代理类(real-class)
public class RealCarFactory implements CarFactoryService {
//被代理逻辑
@Override
public Car produceCar() {
return new Car(1L, "red", "上海轮胎橡胶", "suv", new BigDecimal(115239.28));
}
}
2. 静态代理
静态代理需要定义父类或接口,并要求代理类和被代理类继承相同的父类或实现相同的接口。
2.1 代理类(proxy-static)
public class ProxyStaticCarFactory implements CarFactoryService {
//被代理类
private RealCarFactory realCarFactory;
public ProxyStaticCarFactory(RealCarFactory realCarFactory){
this.realCarFactory = realCarFactory;
}
@Override
public Car produceCar() {
//此处加入增强逻辑 start
//....
//此处加入增强逻辑 end
Car car = this.realCarFactory.produceCar();
//此处加入增强逻辑 start
//....
//此处加入增强逻辑 end
return car;
}
}
2.2 静态代理测试/调用
//静态代理测试
@Test
public void testStaticProxy(){
CarFactoryService proxy = new ProxyStaticCarFactory(new RealCarFactory());
Car car = proxy.produceCar();
}
3. 动态代理
静态代理只是一个基础的应用而已,动态代理才是重中之重,与静态代理相对。动态代理在开发阶段并不需要关心被代理对象是什么,在运行阶段才会生成代理类。我们经常提到的AOP(面向切面编程)背后的核心机制就依赖于动态代理,如果我们要开发属于自己的 AOP 框架,就需要使用动态代理。
3.1 JDK代理
3.1.1 匿名类方式
public class ProxyJdk {
//被代理类
private Object target;
public ProxyJdk(Object RealTarget) {
this.target = RealTarget;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), new InvocationHandler() {
/**
* @param proxy 生成的代理对象
* @param method 需要执行的目标方法
* @param args 需要执行的目标方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//此处加入增强逻辑 start
//....
//此处加入增强逻辑 end
return method.invoke(target, args);
}
});
}
}
3.1.2 显式的实现 InvocationHandler 接口方式
public class ProxyInvocation implements InvocationHandler {
//被代理类
private Object target;
public ProxyInvocation(Object RealTarget) {
this.target = RealTarget;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
/**
* @param proxy 生成的代理对象
* @param method 需要执行的目标方法
* @param args 需要执行的目标方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//此处加入增强逻辑 start
//....
//此处加入增强逻辑 end
return method.invoke(target, args);
}
}
3.2 Cglib代理
3.1.1 实现 MethodInterceptor 接口
public class ProxyCglib implements MethodInterceptor {
//被代理类
private Object target;
public ProxyCglib(Object RealTarget) {
this.target = RealTarget;
}
public Object getProxyInstance(){
//Cglib中的加强器,用来创建动态代理
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(this.target.getClass());
//设置回调,这里相当于是对于代理类上所有方法的调用,都会调用Callback,而Callback则需要实现intercept()方法进行拦截
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//此处加入增强逻辑 start
//....
//此处加入增强逻辑 end
return methodProxy.invokeSuper(object, objects);
}
}
3.3 动态代理测试/调用
//Jdk代理--匿名类
@Test
public void testJdkProxy1(){
ProxyJdk proxyJdk = new ProxyJdk(new RealCarFactory());
CarFactoryService carFactoryService = (CarFactoryService)proxyJdk.getProxyInstance();
Car car = carFactoryService.produceCar();
}
//Jdk代理--实现 InvocationHandler 接口
@Test
public void testJdkProxy2(){
ProxyInvocation proxyInvocation = new ProxyInvocation(new RealCarFactory());
CarFactoryService carFactoryService = (CarFactoryService)proxyInvocation.getProxyInstance();
Car car = carFactoryService.produceCar();
}
//Cglib代理--实现 MethodInterceptor 接口
@Test
public void testCglibProxy(){
ProxyCglib proxyCglib = new ProxyCglib(new RealCarFactory());
CarFactoryService carFactoryService = (CarFactoryService)proxyCglib.getProxyInstance();
Car car = carFactoryService.produceCar();
}
总结
- 目标接口存在父类或实现了接口,使用 Jdk 代理;
- 目标接口不存在父类或未实现接口,使用 cglib 代理;
- 代理模式尤其是动态代理应用特别广泛,大到一个系统架构,小到某个小小的代码片段等,都可能/可以用到代理模式。