原理背景
所谓AOP就是指面向切面编程,通俗地将就是将你要关心的那个类用个代理给包起来,你访问使用时其实是在跟代理打交道。
用下面伪代码表示个意思,不用非常在于原理性正确与否。
user { sayHi()}userProxy { sayHi() { // 随便做点啥 user.sayHi() // 再随便做点啥 }}
有了这个代理技术以后,你可以决定到底是在原来方法前面还是后面进行一些额外的操作。
当然,严格地讲 “代理” 是分为动态代理和静态代理。
静态代理跟上面伪代码差不多,代理类是跟被代理类紧密耦合的,不能用于其他的类,具有一次性特点。
动态代理不一样的地方在于你不用每次都声明一个代理类,这个原本需要你手动敲代码出来的代理类是可以动态生成的,所以称之为“动态代理”。
动态代理Spring常用有两种,1)基于JDK的动态代理;2)基于Cglib第三方库的动态代理。
功能背景介绍
介绍完技术背景,来说下功能背景,数据库读写分离是目前比较常用的一种应对高并发的处理方式,简单好用。
为了达到读写分离,首先要做的是将原有一个的数据源(DataSource),拆分成两个,一个用来读,一个用来写。但是如何让普通开发人员无感呢,就是说还是像原来一个数据源时那样写代码,而不是加一大堆跟业务逻辑没关系的功能性代码。
本文要讲的就是如何采用上面介绍的技术AOP来实现这个功能。
实现
1. 切面定义
首先既然是AOP那么你先得定于出你需要关心的目标,如什么要的类方法你需要特殊照顾,碰到它你就要将数据源切换到写或者切换到读。
网上有很多方式,大部分使用定义的方式,就是先定义出譬如 “select” “query” “find”等开头的就切换到读数据源,但是我觉得这种并不灵活,我个人觉得最佳的方式是使用 注解 Annotation。
因为,第一注解很容易定位目标,即定义成AOP切面,第二注解可以设置属性,这样你就可以方便定义到底是切读还是切写。
2. 新的数据源类
创建一个新的数据源类,保存一个切换标记,下次调用时根据标记来返回读或者写真实的数据源的连接。
3. 切面处理函数
有了切面定义,那么处理函数只要声明为 @Before 之类 就可以了,即在原来方法执行之前先执行处理函数,处理函数主要根据注解里配置的属性对上面的特殊数据源进行标记切换。
注意
- 切换标记一定要注意线程安全,可以使用ThreadLocal。
- 如果使用Spring事务管理的,你的代理一定要在处理事务的代理上进行代理,不然事务并不会起效