一。目的
在组内方便的切换主库和从库
二。具体做法
代码部分改动
1. 增加了一个注解DataSourceChange
public @interface DataSourceChange {
boolean fromSlave() default false;
}
2. 增加了MultipleDataSourceInterceptor
在这个函数里,利用AOP,将当前的DataSourceNameContextHolder 切换到从库上
主要需要关注的代码是
//为了减少影响面,目前只对×Service类里拥有DataSourceChange注解方法 进行AOP
private final static String EDP = "execution(@com.DataSourceChange * com" +
"..*Service.*(..))";
// 这是切换DataSourceNameContextHolder的部分代码
try {
if (fromSlave) {
DataSourceNameContextHolder.set(DataSourceNameConstant.SLAVE);
}
obj = joinPoint.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
} finally {
if (fromSlave) {
DataSourceNameContextHolder.clear();
}
}
3.增加了一个Wrapper
将原来ProductDao的部分方法挪了出来,放在这里,使用方法
@DataSourceChange(fromSlave = true)
public List<String> getIncludeSupplierIds() {
return xxDao.getIncludeSupplierIds();
}
三。验证方法
打开spring连接transaction的日志,查看使用了哪个连接。
四。结论
1. 如何使用
如果想让某个由Spring管理的Service里的某个方法访问从库,只需要给Service加上注解 @DataSourceChange(fromSlave = true), 则这个Service里的方法会自动访问从库。(前提是,Service里的DAO是由spring+mybatis管理的).
譬如
@DataSourceChange(fromSlave = true)
public List<String> fooA() {
return xxx.fooA();
}
2. 不足
我尝试过,将这个注解加到DAO这一层,譬如
@Repository
public interface xxDao {
@DataSourceChange(fromSlave = true)
List<String> fooA();
}
启动时Spring会报错,提示 Could not generate CGLIB subclass of final class.
猜测原因可能是 mybatis 自动生成Mapper类时,使用了CGLIB。 但是在spring再对这个interface进行代理时,必须用JDK默认的proxy才行。。所以这里可能会有冲突。
还希望有别的同学能来指导具体的原因
如果这个service有@Transaction注解时,也不能使用这种方法。。。 这好像是Spring的一个bug,使用Transaction时,只会使用默认的dataSource
(已经由组内其他同事解决了。)