设计模式-代理模式

182 阅读5分钟

代理模式

给A对象,找个替身B,所有请求和响应都经过B完成。

代理模式优缺点

代理模式的优点:

1、职责清晰

2、高扩展性

3、智能化

代理模式缺点:

1、因为加了代理对象,可能造成请求的处理速度变慢

2、代理模式需要额外的工作,稍复杂

代理模式适应场景

1、

2、

代理模式的分类

1、静态代理 静态代理虽然存在一定的缺点,死板,不能动态调整,但是它很重要,源码中很多写法也是使用了静态代理。并且先研究静态代理,知道其缺陷,再去研究动态代理是很有帮助的。所以不要小瞧静态代理。

2、动态代理 在运行期间,可以方便地调整被代理的对象,如可以代理A,也可以代理B。 java 单继承,is-a的体系 。会对动态代理有一定影响,但可以通过操作字节码方式解决问题。 动态代理又有2种方式,JDK 动态代理,CGlib动态代理。

静态代理

被代理对象,target 可以是接口、抽象类,并且有具体的实现

代理类,proxy ,暴露给使用端使用,和被代理对象实现同一个接口或者继承同一个抽象类(因为java是单继承,is-a,如果代理类已经继承了某个类,则不能再继承被代理对象【抽象类】,这是一个限制)

客户端, client , 不直接使用被代理的对象,而是使用代理类完成作业

静态代理的写法,完成对一个接口的代理。

interface Subject{
    
   void work();
   
   // 可以有多个行为
}

// 被代理对象的具体实现
class SubjectImpl implements Subject{
    
    void work(){
        sout("work");
    }
}


// 代理类 , 实现 被代理对象 ,并持有一个被代理对象的实例
class Proxy implements Subject{
    
    Subject target;  // 非常重要,持有被代理对象,在构造函数时候指定,这也意味着,静态代理在编码环境已经确定代理的对象,写法比较死板,达不到在运行期间动态的调整
    
    public Proxy(Proxy target){
        this.target= target;
    }
    
    // 满足开闭
    void work(){
        sout("before"); //代理前增强
        
        target.work();
        
        sout("after"); //代理后增强

    }
    
}

// 使用

class Client {
    
    void main(){
       
        Subject target = new SubjectImpl();
        
        Proxy proxy = new Proxy(target);// 把被代理对象传入到代理类中
        
        proxy.work(); // 使用代理类操作,效果是达到了 target的实现,并且还能做扩展
        
    }
}

从开闭原则视角,再重新考虑,代理模式,就是在不改变原有的情况下,做一些拓展,也可以通过继承的方式来实现。

基于上面的 Subject 和它的一个具体实现 SubjectImpl,为此,我们模拟一种场景,对SubjectImpl进行拓展。用一个代理类,完成 SubjectImpl 的作业,并拓展一些设计模式要活用,这才是设计模式的精髓。马走日,象飞田,可以把这些规则理解成设计模式,但是到整个棋盘上,变化万千了!

采用继承的方式,实现对 代理subjectImpl的作业,并做拓展,如下是伪代码

  // 继承方式实现静态代理 , 不要拘泥于代码的形式,要明白设计模式的本质,会活用
class SubjectProxy extends SubjectImpl{
    
    public void work(){
        sout("静态代理-继承方式 : before work");
        super.work();
        sout("静态代理-继承方式 : after work");
    }
    
}

// 客户端使用
class client {
    
    void main(){
        
        Subject proxy = new SubjectProxy();
        
        proy.work();
        
    }
}

JDK动态代理

实现 IncocationHandler 接口,走invoke()拦截,底层使用 java 反射技术。

代理对象,是个接口 代理类 客户端

// 简单的订单对象,提交订单入参
public class Order {


    private String orderNo;

    private String status;

    private BigDecimal amount;

    private String type="普通订单";

    private String description;

    public Order() {
    }
 }

被代理对象,是一个接口

// 被代理对象
public interface OrderServer {


    /**
     * 下单,被代理的目标方法
     */
    Order buildOrder(Order order);

}

被代理对象的2个具体实现,

// 普通订单
public class DefaultOrderHandler implements OrderServer{

    @Override
    public Order buildOrder(Order order) {

        Order od  = order;

        od.setAmount(new BigDecimal("1000"));
        od.setStatus("待付款");
        return od;
    }
}


// 用券订单
public class CouponOrderHandler implements OrderServer{

    @Override
    public Order buildOrder(Order order) {
        Order od  = order;

        od.setAmount(new BigDecimal("600")); // 模拟用券,比普通订单金额少了400
        od.setStatus("待付款");

        System.out.println(" have built an order  with coupon ... ... ... ... ");
        return od;
    }
}

代理类, 实现 JDK的 InvocationHandler 接口,实现invoke() 使用Proxy.newProxyInstance() 构建代理类

//
public class InvocationHandlerOrder implements InvocationHandler {


    private Object os;

    public InvocationHandlerOrder(Object os){
        this.os = os; // 构造函数指定具体干事的 即代理对象的具体实现
    }
    

    public void setOs(Object os) {
        this.os = os;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK代理-invoke before"); // 代理前置增强

        Object result =null;
      
        // jvm 加 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 查看字节码
        //result = method.invoke(proxy, args); // 死循环 
        
        result = method.invoke(this.os, args);
        
        System.out.println("JDK代理-invoke after ... "); // 代理后置增强

        return result;
    }
}


// 构建订单 使用一个工厂方式,
public class OrderFactory {

    public static Object getProxy(Object targetObject){

        ClassLoader loader = targetObject.getClass().getClassLoader();
        Class<?>[] interfaces = targetObject.getClass().getInterfaces();
        InvocationHandler h = new InvocationHandlerOrder(targetObject);// 实例化代理类对象
        
        // Proxy.newProxyInstance() 构建代理类
        return Proxy.newProxyInstance(
                loader,//目标对象的类加载器
                interfaces,//获取目标对象实现的接口
                h//将目标对象传递到JDK动态代理类的构造方法中,进行创建一个动态代理类的实例对象
        );
    }
}

客户端使用(业务聚合层使用领域层)

// client 调用
public static void jdkProxy(){
    Order od = new Order();
    od.setOrderNo("2022-04-08-15-100");
    od.setStatus("草稿");
    OrderServer  target =new CouponOrderHandler(); // 正在干事的,被代理对象的具体实现

    OrderServer proxy = (OrderServer)OrderFactory.getProxy(target);

    Order or=proxy.buildOrder(od);
    System.out.println(or);
}

// main 方式运行结果如下:
JDK代理-invoke before                   【代理的前置增强】
 have built an order  with coupon ... ... ... ...    【真正干事的】
JDK代理-invoke after ... 【代理的后置增强】
Order{orderNo='2022-04-08-15-100', status='待付款', amount=600, type='普通订单', description='null'}
 the end
 
 

CgLib动态代理

1、 底层使用字节码技术 ASM框架。

JDK动态代理和Cglib 动态代理比较

源码中动态代理的使用

spring aop

dubbo