- 为其他对象提供一种代理,以控制对这个对象的访问
- 代理对象在客户端与目标对象之间起到中介的作用
- 能够将代理对象与真实被调用的目标对象分离
- 一定程度上降低了系统的耦合度,扩展性好
- 可以保护目标对象
- 对目标对象增强(Spring AOP)
- 代理模式会再次系统设计中类的数目增加
- 加入中间层,请求变慢
- 增加字体的复杂度
- 静态代理
- 动态代理
- JDK动态代理(代理接口,并且只有在程序运行中动态创建的代理类)
- CGLib动态代理(针对类实现,实现方式是创建一个子类来重写父类的方法,如果是final的就会无法被继承)
- 当Spring的Bean有实现接口的时候,Spring就会使用JDK动态代理
- 当Bean没有实现接口的时候,Spring就会使用CGLib
- 强制使用CGlib的方法是
<aop:aspectj-autoproxy proxy-target-class="true"/> - CGLib
- 使用ASM动态生成字节码(比反射效率高)
- JDK动态代理
在万次执行测试中,JDK动态代理要比CGLib动态代理快20%左右
- 装饰者模式
- 装饰者模式是为对象加上行为
- 代理模式是控制访问
- 适配器模式
- 改变接口的表现
针对Order实体,有对应的Dao层IOrderDao其对应的实现是OrderDaoImpl,Service层IOrderService实现类是OrderServiceImpl,现在要代理类完成的需求是
实现分库,简单起见,使用Order的id取模,将记录传入到不同的库中,为了实现这样一个功能,可以使用代理,这个代理封装了具体的实现。下面是分库的具体实现
- 分库必然需要多个数据源,那么需要能决定分到具体数据源的抽象层,其必然维护相关的数据源,这个抽象层就是
AbstractRoutingDataSource - 分库逻辑决定了将数据分配到哪里,如果通过直接传参的方式和数据源耦合过密,所以使用ThreadLocal来作为约定传递
- 首先要想使用JDK动态代理,需要做两件事情:
- 代理类实现
InvocationHandler接口,该接口只有一个public Object invoke(Object proxy, Method method, Object[] args)方法- invoke函数的第一个参数是生成的代理类对象(JDK生成),第二个是Method,第三个是方法传入的参数
- 使用Proxy 静态方法来获取生成的代理类
- 代理类实现
- Spring中的
JdkDynamicAopProxy以及CglibAopProxy - MyBatis 的
MapperRegistry中的getMapper(Class<?> clazz)
