定义: 为其他对象提供一种代理,以控制对这个对象的访问
代理对象在客户端和目标对象之间起到中介的作用
类型: 结构性
适用场景
1、保护目标对象
2、增强目标对象
优点
代理模式能将代理对象与真实被调用的目标对象分离
一定程度上降低了系统的耦合度,扩展性好
保护目标对象
增强目标对象(如加before和after)
缺点:
代理模式会造成系统设计中类数目增加
在客户端和目标对象增加一个代理对象,会造成请求速度变慢
增加系统的复杂度
代理-扩展
静态代理
动态代理
CGLib代理
Spring 代理选择-扩展
当Bean有实现接口时,Spring就会用JDK的动态代理
当Bean没有实现接口时,Spring使用CGlib
可以强制使用Cglib
在spring配置中加入 <aop:aspectj-autoproxy proxy-target-class="true" />
静态代理实践(另外一个静态代理的例子Spring AOP原理)
1、创建实体Order
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; } }
2、创建Dao层
IOrderDao接口
public interface IOrderDao { int insert(Order order); }
IOrderDao接口实现
public class OrderDaoImpl implements IOrderDao { @Override public int insert(Order order) { System.out.println("Dao层添加Order成功"); return 1; } }
3、创建服务层
创建IOrderService 接口
public interface IOrderService { int saveOrder(Order order); }
创建IOrderService 接口实现
public class OrderServiceImpl implements IOrderService{ private IOrderDao iOrderDao; @Override public int saveOrder(Order order) { //Spring会自己注入,这里就直接注入了 iOrderDao = new OrderDaoImpl(); System.out.println("Service层调用Dao层添加Order"); return iOrderDao.insert(order); } }
4、模拟Spring中分库的使用介绍
创建DynamicDataSource
public class DynamicDataSource extends AbstractRoutingDataSource{ /** * 返回值代表使用哪个Db * @return */ @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDBType(); } }
创建DataSourceContextHolder
public class DataSourceContextHolder { private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); public static void setDBType(String dbType){ CONTEXT_HOLDER.set(dbType); } public static String getDBType(){ return (String) CONTEXT_HOLDER.get(); } public static void clearDBType(){ CONTEXT_HOLDER.remove(); } }
5、创建代理类
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){ System.out.println("静态代理 before code"); int userId = order.getUserId(); int dbRouter = userId % 2; System.out.println("静态代理分配到【db" + dbRouter + "】处理数据"); // TODO: 2020/1/27 设置dataSource DataSourceContextHolder.setDBType("db" + String.valueOf(dbRouter)); } private void afterMethod(){ System.out.println("静态代理 after code"); } }
6、测试
public class Test { public static void main(String[] args) { Order order = new Order(); order.setUserId(2); OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy(); orderServiceStaticProxy.saveOrder(order); } }
7、UML图如下
8、输出结果如下
静态代理 before code 静态代理分配到【db0】处理数据 静态代理 after code Service层调用Dao层添加Order Dao层添加Order成功
动态代理实践(另外一个动态代理的例子Spring AOP原理)
1、创建动态代理类
public class OrderServiceDynamicProxy implements InvocationHandler{ private Object target; public OrderServiceDynamicProxy(Object target){ this.target = target; } public Object build(){ 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: 2020/1/27 设置dataSource DataSourceContextHolder.setDBType("db" + String.valueOf(dbRouter)); } private void afterMethod(){ System.out.println("动代理 after code"); } }
2、测试
public class Test { public static void main(String[] args) { Order order = new Order(); order.setUserId(2); IOrderService orderServiceDynamicProxy = (IOrderService)new OrderServiceDynamicProxy(new OrderServiceImpl()).build(); orderServiceDynamicProxy.saveOrder(order); } }
3、输出
动态代理 before code 动态代理分配到【db0】处理数据 Service层调用Dao层添加Order Dao层添加Order成功 动代理 after code
代理模式在源码中的应用
1、JDK中的java .lang.reflet.Proxy类
2、Spring中的ProxyFactoryBean
核心的方法为getObject()
还有JdkDynamicAopProxy和CglibAopProxy
3、Mybatis中
MapperProxyFactory
作者:Work Hard Work Smart
出处:http://www.cnblogs.com/linlf03/
欢迎任何形式的转载,未经作者同意,请保留此段声明!