java设计模式精讲 Debug 方式+内存分析 第16章 代理模式讲解

本文深入解析代理模式,通过静态代理和动态代理实现分库功能,详细介绍了代理模式在代码中的应用,包括静态代理的具体实现和动态代理的灵活运用,以及如何在实际业务场景中通过代理模式进行数据库路由。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

16-1 代理模式讲解

可以理解为房东和中介的关系:
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


静态代理就是在代码中显示指定的代理;
动态代理无法代理类,但是可以代理接口;
在使用CGLib代理的时候,因为要用到继承,还有重写,所以对final的这个关键字的时候一定要格外的注意:
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


16-2 代理模式coding-静态代理-1

这里引入的就是分库的一个业务场景:

  1. 首先有一个订单类:
public class Order {
    private Object orderInfo;
    private Integer userId;

    public Object getOrderInfo() {
        return orderInfo;
    }

    public void setOrderInfo(Object orderInfo) {
        this.orderInfo = orderInfo;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }
}
  1. Dao层的接口:
public interface IOrderDao {
    int insert(Order order);
}
  1. Dao层的实现:
public class OrderDaoImpl implements IOrderDao {
    @Override
    public int insert(Order order) {
        System.out.println("Dao层添加order成功");
        return 1;
    }
}
  1. Service层的接口:
public interface IOrderService {
    /** 保存订单,参数为订单对象,返回值为生效行数 */
    int saveOrder(Order order);
}
  1. Service层的实现:
public class OrderServiceImpl implements IOrderService {

    private IOrderDao iOrderDao;

    @Override
    public int saveOrder(Order order) {
        /** Spring会自己注入,我们这里就直接new出来了 */
        iOrderDao = new OrderDaoImpl();
        System.out.println("Service调用Dao层添加Order层");
        return iOrderDao.insert(order);
    }
}

有一个ThreadLocal:

public class DataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

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

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

    public static void clearDBType() {
        CONTEXT_HOLDER.remove();
    }
}

Spring里面的分库:

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

还有一个静态代理类:

public class OrderServiceStaticProxy {
    /**  在代理类里面注入目标对象 */
    private IOrderService iOrderService;

    /** 我们要在这静态代理类里面增强这个方法 */
    public int saveOrder(Order order){
        beforeMethod();
        /** 如果这里有spring容器的话,就不用显示的new了 */
        iOrderService = new OrderServiceImpl();
        int userId = order.getUserId();
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");

        //todo 设置dataSource;
        DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
        
        afterMethod();
        return iOrderService.saveOrder(order);
    }

    /** 我们要增强,我们就来写上一个before和after */
    private void beforeMethod(){
        System.out.println("静态代理 before code");
    }

    private void afterMethod(){
        System.out.println("静态代理 after code");
    }
}

16-3 代理模式coding-静态代理-2


在这里插入图片描述

测试代码如下:

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(1);
        /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
        OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
        orderServiceStaticProxy.saveOrder(order);
    }
}

执行结果:

静态代理 before code
静态代理分配到【db1】处理数据
静态代理 after code
Service调用Dao层添加Order层
Dao层添加order成功

当我们把id改成2的时候:

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(2);
        /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
        OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
        orderServiceStaticProxy.saveOrder(order);
    }
}

执行结果如下:

静态代理 before code
静态代理分配到【db0】处理数据
静态代理 after code
Service调用Dao层添加Order层
Dao层添加order成功

和我们的预期是一样的,这就实现了一个分库的功能;
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


16-4 代理模式coding-动态代理

这个就是一个动态代理的类:

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);
    }

    @Override
    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;
    }

    public void beforeMethod(Object obj) {
        int userId = 0;
        System.out.println("动态代理before code");
        if (obj instanceof Order) {
            Order order = (Order) obj;
            userId = order.getUserId();
        }
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("动态代理分配到【db"+dbRouter+"】处理数据");
        //todo 设置dataSource;
        DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
    }
    public void afterMethod() {
        System.out.println("动态代理after core");
    }
}

我们来写一个测试类:

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(2);
        /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
        IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
        orderServiceDynamicProxy.saveOrder(order);
    }
}

执行结果:

动态代理before code
动态代理分配到【db0】处理数据
Service调用Dao层添加Order层
Dao层添加order成功
动态代理after core

而当我们把id改成1的时候:

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(1);
        /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
        IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
        orderServiceDynamicProxy.saveOrder(order);
    }
}

分到了db1的这个库里面:

执行结果:
动态代理before code
动态代理分配到【db1】处理数据
Service调用Dao层添加Order层
Dao层添加order成功
动态代理after core


16-5 代理模式源码解析(jdk+spring+mybatis)

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值