代理模式
2010 年 11 月 30 日
一、代理模式介绍
1、定义与类型
定义:为其他对象提供一种代理,以控制对这个对象的访问
代理对象在客户端和目标对象之间起到中介的作用
类型:结构型
2、适用场景
保护目标对象
增强目标对象
3、优点
代理模式能将代理对象与真实被调用的目标对象分离
一定程度上降低了系统的耦合度,扩展性好
保护目标对象
增强目标对象
4、缺点
代理模式会造成系统设计中类的数目增加
在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
增加系统的复杂度
5、扩展
静态代理
动态代理
CGLib代理
6、Spring代理选择-扩展
当Bean有实现接口时,Spring就会用JDK的动态代理
当Bean没有实现接口时,Spring使用CGlib
可以强制使用Cglib
在spring配置中加入
参考资料: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(动态代理)