代理模式

一、代理模式介紹

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(動態代理)