【设计模式】代理模式

  |   0 评论   |   43 浏览

简介

为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介的作用,使用代理可以简单的转发到实际对象,也可以提供额外的逻辑,这个完全取决于你的代理类是怎么实现的。代理类可以提供额外的功能,比如如果实际对象需要消耗很多资源那么代理类可以进行缓存,也可以在调用实际对象之前作参数验证等。
对于客户端,他们在使用代理类的时候,就感觉是在使用实际的对象,因为代理类和实际对象拥有相同的接口,该模式属于结构型。

适用场景

1、需要对对象的访问进行控制。
2、访问对象时应该提供额外的功能(增强目标对象)。
3、保护目标对象

优点

1、可以代替另一个对象
2、代理对象与真实被调用的对象进行分离
3、一定程度降低了系统的耦合度,扩展性好
4、保护目标对象
5、增强目标对象

缺点

1、系统中类的数目增加
2、造成请求速度变慢
3、增加系统的复杂度

扩展

1、静态代理
在代码中显式的定义了业务实现类的代理,在代理类中使用实际对象中相同的方法,让客户端可以使用代理类的方法来调用实际对象类。
2、动态代理
对接口的方法动态生成接口中的同名方法,来进行调用,注意:这里必须是接口。
3、CGLib代理
通过继承来实现的,生成的代理类就是业务类的子类,然后重写业务方法来进行代理。
使用注意点:
1、final方法不能被代理
2、代理对象的构造函数将被调用两次,CGLib会对每个代理对象生成一个子类
3、你需要CGBlib二进制文件在classpath下面,然而动态代理在jdk中依旧可用,Spring会发出警告,如果它没有发现GBLib的类在classpth里面。

spring扩展

1、当Bean有实现接口时,Spring就会用JDK的动态代理
2、当Bean没有实现接口时,Spring使用CGLib
可以强制使用CGLib

<aop:aspectj-autoproxy proxy-target-class="true" />

代码示例

静态代理

image.png
订单接口

public interface OrderService {
    String saveOrder(Integer userId);
}

订单实现类

public class OrderServiceImpl implements OrderService{
    public String saveOrder(Integer userId) {
        System.out.println("创建订单,用户id为:"+userId);
        return "sn123456";
    }
}

静态代理类

public class OrderServiceStaticProxy {
    private OrderService orderService;
    public String saveOrder(Integer userId) {
        methodBefore();
        if(null == orderService){
            orderService = new OrderServiceImpl();
        }
        String orderNo = orderService.saveOrder(userId);
        methodAfter();
        return orderNo;
    }
    private void methodBefore(){
        System.out.println("订单前校验参数");
    }
    private void methodAfter(){
        System.out.println("订单完成之后做点什么事情");
    }
}

测试类

public class StaticProxyTest {
    public static void main(String[] args) {
        OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
        orderServiceStaticProxy.saveOrder(1);
    }
}

输出结果:

订单前校验参数
创建订单,用户id为:1
订单完成之后做点什么事情

动态代理

对相同功能的处理不需要创建多个类,只需要一个动态代理类就可以了,但是静态代理类需要创建多个类。
image.png
订单类

public class Order {
    private Integer userId;
    private String orderNo;
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getOrderNo() {
        return orderNo;
    }
    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }
    @Override
    public String toString() {
        return "Order{" +
                "userId=" + userId +
                ", orderNo='" + orderNo + '\'' +
                '}';
    }
}

订单接口

public interface OrderService {
    Order saveOrder(Order order);
}

订单实现类

public class OrderServiceImpl implements OrderService{
    public Order saveOrder(Order order) {
        order.setOrderNo("sn123");
        System.out.println("保存订单数据");
        return order;
    }
}

动态代理类

public class OrderServiceDynamicProxy implements InvocationHandler {
    private Object target;
    public OrderServiceDynamicProxy(Object target) {
        this.target = target;
    }
    public Object bind(){
        Class cls = target.getClass();
        return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object argObject = args[0];
        beforeMethod(argObject);
        Object object = method.invoke(target,args);
        afterMethod();
        return object;
    }
    private void beforeMethod(Object obj){
        if(obj instanceof Order){
            Order order = (Order)obj;
            System.out.println("保存之前订单参数进行校验");
        }
    }
    private void afterMethod(){
        System.out.println("保存成功之后做点事情");
    }
}

测试类

public class DynamicProxyTest {
    public static void main(String[] args) {
        Order order = new Order();
        order.setUserId(1);
        OrderService proxy = (OrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
        order = proxy.saveOrder(order);
        System.out.println("订单数据"+order);
    }
}

输出结果

保存之前订单参数进行校验
保存订单数据
保存成功之后做点事情
订单数据Order{userId=1, orderNo='sn123'}

上面示例源码

源码分析

jdk中应用

Proxy类就是代理的实现。

spring中应用

image.png

mybatis中应用

image.png
image.png

也可以关注我的公众号:程序之声
图片
关注公众号,领取更多资源

本文为博主原创文章,未经博主允许不得转载。

评论

发表评论