代理模式

一、代理模式介绍

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(动态代理)

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章