打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

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

代理模式

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)






本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
代理模式
我在项目内使用了设计模式后,同事直呼看不懂
jdk动态代理类
Wiring Your Web Application with Open Source Java
eclipse下struts+spring+hibernate快速入门
Hibernate3与spring的整合应用-技术学习者
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服