• 代理模式


    一、代理模式介绍

    1、定义与类型

    定义:为其他对象提供一种代理,以控制对这个对象的访问
    代理对象在客户端和目标对象之间起到中介的作用
    类型:结构型

    2、适用场景

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

    3、优点

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

    4、缺点

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

    5、扩展

    静态代理
    动态代理
    CGLib代理

    6、Spring代理选择-扩展

    当Bean有实现接口时,Spring就会用JDK的动态代理
    当Bean没有实现接口时,Spring使用CGlib
    可以强制使用Cglib
    在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
    参考资料:htpsi//docs.spring.io/spring/docs/current/spring-framework-reference/core.html

    7、代理-相关设计模式

    代理模式和装饰者模式
    实现上相似,但目的不同,装饰者模式是为对象加上行为,而代理模式是为了控制访问,代理模式更加注重通过增加代理人的方式来增强目标对象。

    代理模式和适配器模式
    适配器模式主要考虑改变目标对象的接口,而代理模式是不能改变代理类的接口的

    二、代码示例

    模拟场景:spring中,service调用dao前,需要先根据分库策略,切换数据源,即AOP面向切面

    实体订单类:

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

    持久层dao接口:

    public interface IOrderDao {
        int insert(Order order);
    }
    

    持久层dao实现类:

    public class OrderDaoImpl implements IOrderDao {
        @Override
        public int insert(Order order) {
            System.out.println("Dao层添加Order成功");
            return 1;
        }
    }
    

    服务层service接口:

    public interface IOrderService {
        int saveOrder(Order order);
    }
    

    服务层service类:

    public class OrderServiceImpl implements IOrderService {
        private IOrderDao iOrderDao;
        @Override
        public int saveOrder(Order order) {
            //模拟自动注入
            iOrderDao = new OrderDaoImpl();
            System.out.println("Service层调用Dao层添加Order");
            return iOrderDao.insert(order);
        }
    }
    

    1、静态代理

    静态代理类:

    public class OrderServiceStaticProxy {
        private IOrderService iOrderService;
    
        public int saveOrder(Order order){
            beforeMethod(order);
            // 模拟自动注入
            iOrderService = new OrderServiceImpl();
            int result = iOrderService.saveOrder(order);
            afterMethod();
            return result;
        }
    
        private void beforeMethod(Order order){
            // 模拟分库代理操作
            int userId = order.getUserId();
            int dbRouter = userId % 2;
            System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");
    
            //todo 设置dataSource;
            DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
            System.out.println("静态代理 before code");
        }
    
        private void afterMethod(){
            System.out.println("静态代理 after code");
        }
    }
    

    测试类:

    public class Test {
        public static void main(String[] args) {
            Order order = new Order();
            order.setUserId(2);
            
            //直接调用代理类
            OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
            orderServiceStaticProxy.saveOrder(order);
        }
    }
    

    2、动态代理

    动态代理类:

    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;
        }
    
        private void beforeMethod(Object obj){
            int userId = 0;
            System.out.println("动态代理 before code");
            if(obj instanceof Order){
                Order order = (Order)obj;
                userId = order.getUserId();
            }
            int dbRouter = userId % 2;
            System.out.println("动态代理分配到【db"+dbRouter+"】处理数据");
    
            //todo 设置dataSource;
            DataSourceContextHolder.setDBType("db"+String.valueOf(dbRouter));
        }
    
        private void afterMethod(){
            System.out.println("动态代理 after code");
        }
    }
    

    测试类:

    public class Test {
        public static void main(String[] args) {
            Order order = new Order();
            order.setUserId(1);
    // 通过代理类取到service
            IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
    
            orderServiceDynamicProxy.saveOrder(order);
        }
    }
    

    三、 源码示例

    1、spring中的ProxyFactoryBean(静态代理)

    2、mybatis中的MapperProxy(动态代理)

  • 相关阅读:
    准备 FRM 考试——方法、工具与教训
    930. 和相同的二元子数组 前缀和
    1906. 查询差绝对值的最小值 前缀和
    剑指 Offer 37. 序列化二叉树 二叉树 字符串
    815. 公交路线 BFS
    518. 零钱兑换 II dp 完全背包
    1049. 最后一块石头的重量 II dp
    5779. 装包裹的最小浪费空间 二分
    5778. 使二进制字符串字符交替的最少反转次数 字符串 滑动窗口
    474. 一和零 dp
  • 原文地址:https://www.cnblogs.com/weixk/p/12996346.html
Copyright © 2020-2023  润新知