定义
为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用。即为指定的目标对象提供一个代理商,由代理商来完成对目标对象的操作。
打个比方,帮别人做事情,自己就是别人的代理;让别人帮自己做事情,别人就是自己的代理。
代理又分为静态代理,动态代理,CGLib代理。
类型
结构型
适用场景
- 保护目标对象。在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 增强目标对象。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。
优点
- 代理模式能将代理对象与真实被调用的目标对象分离
- 一定程度上降低了系统的耦合度,扩展性好
- 保护目标对象
- 增强目标对象
缺点
- 代理模式会造成系统设计中类的数目增加
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度减慢
- 增加系统的复杂度
UML类图
Subject抽象类:普通的业务类型的定义,规定要做什么事情。也可以是一个接口。
RealSubject具体类(被代理类):真正业务处理的执行者。
Proxy代理类:负责对真实角色的调用,也可以在被代理类处理前做一些预处理,或在被代理类处理后做一些善后处理(比如Spring的AOP)。
代码Demo
- 静态代理
Subject
public interface Subject {
void doSomething();
}
ConcreteSubject
public class ConcreteSubject implements Subject {
@Override
public void doSomething() {
System.out.println("业务操作");
}
}
ProxySubject
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject){
this.subject = subject;
}
@Override
public void doSomething() {
System.out.println("业务操作前的处理");
subject.doSomething();
System.out.println("业务操作后的处理");
}
}
通过组合的方式,对目标对象进行增强,优点是符合开闭原则,增强方法不用在原方法上进行改动,缺点是代理类和被代理类及其业务逻辑耦合,适用性较差且代理逻辑难以扩展,如果有多个代理类(不同接口)需要增强,就需要另外再添加代理类,不宜管理。
- 动态代理
ProxySubject
public class ProxySubject implements InvocationHandler {
private Object obj;
public ProxySubject(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置通知");
Object ret = method.invoke(obj,args);
System.out.println("后置通知");
return ret;
}
}
Test
public class Test {
public static void main(String[] args) {
Subject sub = new ConcreteSubject();、
//ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
//Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
//InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
Subject proxy = (Subject) Proxy.newProxyInstance(sub.getClass().getClassLoader(), sub.getClass().getInterfaces(),
new ProxySubject(new ConcreteSubject()));
proxy.doSomething();
}
}
与静态代理相比,动态代理可以在不知道被代理类的前提下编写代理逻辑,运行时才决定被代理对象,适用性好且代理逻辑易于扩展,另外如果我们要对其他类进行代理,只需要修改下客户端代码就行。
- CGLIB代理(导入cglib相关依赖)
public class ConcreteSubject{
public void doSomething() {
System.out.println("业务操作");
}
}
public class CglibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前处理");
Object ret = methodProxy.invokeSuper(obj, objects);
System.out.println("后处理");
return ret;
}
}
public class Test {
public static void main(String[] args) {
/*
* 创建字节码增强器
*/
Enhancer enhancer = new Enhancer();
/*
* 被代理类设置为字节码增强器父类,cglib使用的是继承方式去创建代理类
*/
enhancer.setSuperclass(ConcreteSubject.class);
/*
* 设置字节码增强器回调方法。对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦截
*/
enhancer.setCallback(new CglibDynamicProxy());
/*
* 创建代理实例
*/
ConcreteSubject proxy= (ConcreteSubject) enhancer.create();
proxy.doSomething();
}
}
与前两个方法相比,CGLIB可以为所以类生成代理,但是它的速度没有JDK的动态代理来的快。
JDK动态代理源码分析
https://www.cnblogs.com/zhangchengzi/p/9713807.html