之前介绍了多数据源的接入,参见 Multiple Datasource ,后来一个数据分析的项目(大部分都是读操作)需要用到读写分离,在分析时读取从库的数据,避免增加对线上数据库的压力,少部分写操作依然写主库,然后再被同步至从库,根据同事的建议,希望采用注解方式实现,从而在开发时只需加上特定的注解即可表明此 DAO 操作主库还是从库,原理依然与之前类似,以下是调整的部分:
定义主从数据库的枚举,因为项目中大多数走从库,所以吧 SLAVE 写在了第一个
1
2
3
4
5
6
7/**
* Created by Poison on 8/15/2016.
*/
public enum Database {
SLAVE,
MASTER
}定义切换数据源的注解,注解基础可参见 Lesson: Annotations ,根据同事需要只定义了类级别的注解,保留到运行时,读者完全可以根据自身需要自由发挥
1
2
3
4
5
6
7
8
9
10
11/**
* Created by Poison on 8/16/2016.
* This is a marker annotation.
* Use this annotation on DAO interface level, represent that all methods in this interface will operate your specified database.
*/
public DataSource {
Database value() default Database.SLAVE;
}修改 AOP 相关代码,只有在 DAO 接口上应用了 @DataSource 注解,并且注解值为 Database.MASTER 时才走主库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32/**
* Created by Poison on 8/15/2016.
*/
public class AroundDataSource {
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
Object result;
if (hasMasterAnnotation(pjp)) {
DataSourceContextHolder.setDataSource(Database.MASTER);
result = pjp.proceed();
DataSourceContextHolder.restoreToSlaveDataSource();
} else {
result = pjp.proceed();
}
return result;
}
private boolean hasMasterAnnotation(ProceedingJoinPoint pjp) {
Class<?> declaringClass = ((MethodSignature) pjp.getSignature()).getMethod().getDeclaringClass();
if (declaringClass.isAnnotationPresent(DataSource.class)) {
DataSource dataSource = declaringClass.getAnnotation(DataSource.class);
if (dataSource.value() == Database.MASTER) {
return true;
}
}
return false;
}
}