设计模式-代理模式

代理模式

1.定义与类型

  • 为其他对象提供一种代理,以控制这么对象的访问
  • 代理对象在客户端和目标对象之间起中介作用
  • 类型:增强型

2.适用场景

  • 保护目标对象
  • 增强目标对象

3.优点

  • 代理模式能将代理对象与真实对象被调用的目标对象分离
  • 一定程度上降低了代码的耦合度,扩展性好
  • 保护目标对象
  • 增强目标对象

4.缺点

  • 代理模式会造成系统设计中类的数目增加
  • 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
  • 增加系统的复杂度

5.扩展

  • 静态代理
  • 动态代理(Jdk中只有实现接口的类代理)
  • CGlib代理
  • image-20211011211714276

6.相关设计模式

  • 代理模式和装饰者模式
  • 代理模式和适配器模式

7. Coding

7.1 静态代理

  • 创建common的dao service层,见代码

    • 订单实体类Order
    public class Order {
        private String orderInfo ;
        private Integer userId;
    
        public String getOrderInfo() {
            return orderInfo;
        }
    
        public void setOrderInfo(String orderInfo) {
            this.orderInfo = orderInfo;
        }
    
        public Integer getUserId() {
            return userId;
        }
    
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    
        @Override
        public String toString() {
            return "Order{" +
                    "orderInfo='" + orderInfo + '\'' +
                    ", userId=" + userId +
                    '}';
        }
    }
    
    • servie层接口及实现类
    public interface IOrderService {
        int saveOrder(Order order);
    }
    
    public class IOrderServiceImpl implements IOrderService {
    
        private IOrderDao orderDao;
    
        @Override
        public int saveOrder(Order order) {
            orderDao = new IOrderDaoImpl();
            System.out.println("Service层调用Dao层添加Order");
            return orderDao.insert(order);
    
        }
    }
    
    • dao层接口及实现类
    public interface IOrderDao {
        int insert(Order order);
    }
    
    public class IOrderDaoImpl implements IOrderDao{
    
    
        @Override
        public int insert(Order order) {
            System.out.println("Dao层添加订单成功!");
            return 1;
        }
    }
    
  • 创建代理类

public class OrderServiceStaticProxy {
    private IOrderService orderService;

    public void saveOrder(Order order) {
        beforeProxy();
        // 分库
        orderService = new IOrderServiceImpl();
        Integer userId = order.getUserId();
        int dbNum = userId % 2;
        System.out.println("静态代理分配到【db" + dbNum + "】处理数据");
        // 设置分配的数据库
        DataSourceContentHolder.setDBType("db" + dbNum);
        afterProxy();

        orderService.saveOrder(order);
    }

    public void beforeProxy() {
        System.out.println("前置代理类增强方法");
    }

    public void afterProxy() {
        System.out.println("后置代理类增强方法");
    }
}
  • 模拟Spring分库
public class DataSourceContentHolder {
    private static final ThreadLocal<String> CONTENT_HOLDER = new ThreadLocal<>();

    public static void setDBType(String dbType) {
        CONTENT_HOLDER.set(dbType);
    }

    public static String getDBType() {
        return CONTENT_HOLDER.get();
    }

    public static void remove() {
        CONTENT_HOLDER.remove();
    }

}
public class DynamicDaraSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContentHolder.getDBType();
    }
}

  • Test测试
public class Test {
    public static void main(String[] args) {
        Order order = new Order();
        order.setUserId(1);
        OrderServiceStaticProxy staticProxy = new OrderServiceStaticProxy();
        staticProxy.saveOrder(order);
    }
}

控制台输出:

image-20211011221651833

  • UML类图

image-20211011221006034

现在可以看到,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。

上面介绍的是静态代理的内容,为什么叫做静态呢?因为它的类型是事先预定好的。

代理的目的:增强/扩展目标方法

7.2 动态代理

  • public class OrderServiceDynamicProxy implements InvocationHandler {
        private Object target;
    
        public OrderServiceDynamicProxy(Object obj) {
            this.target = obj;
        }
    
        /** 生成代理对象 */
        public Object getTarget() {
            Class<?> clz = target.getClass();
            return Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object arg = args[0];
            beforeProxy(arg);
            // 增强目标方法
            Object object = method.invoke(target,arg);
            afterProxy();
            return object;
        }
    
        public void beforeProxy(Object obj) {
            System.out.println("动态代理before");
            int userId = 0;
            if (obj instanceof Order) {
                Order order = (Order) obj;
                userId = order.getUserId();
            }
            int dbNum = userId % 2;
            System.out.println("动态代理分配到【db" + dbNum + "】处理数据");
            // 设置分配的数据库
            DataSourceContentHolder.setDBType("db" + dbNum);
    
        }
    
        public void afterProxy(){
            System.out.println("动态代理after");
        }
    }
    
  • 测试方法

public class TestDynamicProxy {
    public static void main(String[] args) {
        Order order = new Order();
        order.setUserId(2);
        IOrderService dynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new IOrderServiceImpl()).getTarget();
        dynamicProxy.saveOrder(order);

    }
}
  • 请注意

// JDK中的代理只能对接口代理 否则会报错
IOrderServiceImpl dynamicProxy = (IOrderServiceImpl) new OrderServiceDynamicProxy(new IOrderServiceImpl()).getTarget();

image-20211012200246977

有兴趣的可以手动debug一下这个代码~

7.3 Cglib代理

  • 创建Cglib代理类
public class CglibProxy implements MethodInterceptor {

    public Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        beforeProxy(o);
        Object invoke = methodProxy.invokeSuper(o, objects);
        afterProxy();
        return invoke;
    }

    public void beforeProxy(Object obj) {
        System.out.println("Cglib动态代理before");
        int userId = 0;
        if (obj instanceof Order) {
            Order order = (Order) obj;
            userId = order.getUserId();
        }
        int dbNum = userId % 2;
        System.out.println("动态代理分配到【db" + dbNum + "】处理数据");
        // 设置分配的数据库
        DataSourceContentHolder.setDBType("db" + dbNum);
    }

    public void afterProxy(){
        System.out.println("动态代理after");
    }
}
  • 测试类
public class TestDynamicProxy {
    public static void main(String[] args) {
        Order order = new Order();
        order.setUserId(2);
        CglibProxy cglibProxy = new CglibProxy();
        IOrderServiceImpl service = (IOrderServiceImpl) cglibProxy.getProxy(IOrderServiceImpl.class);
        service.saveOrder(order);
    }
}
  • 输出

image-20211014152509390

8.源码

Mybatis中的应用

  • MapperProxyFactoryimage-20211014154111603

  • 代理模式image-20211012202711709

    • 同时用到了享元模式(cachedMapperMethod(method))image-20211012203109233
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值