代理模式

定义

为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用。即为指定的目标对象提供一个代理商,由代理商来完成对目标对象的操作。

打个比方,帮别人做事情,自己就是别人的代理;让别人帮自己做事情,别人就是自己的代理。

代理又分为静态代理动态代理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 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值