设计模式-代理模式

Posted 一菜一汤

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-代理模式相关的知识,希望对你有一定的参考价值。

代理模式

1.定义与类型

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

2.适用场景

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

3.优点

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

4.缺点

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

5.扩展

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

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

控制台输出:

  • UML类图

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

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

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

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

有兴趣的可以手动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);
    

  • 输出

8.源码

Mybatis中的应用

  • MapperProxyFactory

  • 代理模式

    • 同时用到了享元模式(cachedMapperMethod(method))

以上是关于设计模式-代理模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式——代理模式

设计模式代理模式 ( 代理模式结构 | 客户端 | 主题对象 | 被代理对象 | 代理对象 )

设计模式-代理模式

代理的模式和原理(代理的模式有几种)

设计模式 结构型模式 -- 代理模式模式实例:日志文件

设计模式之代理模式