原理:主要是调用目标方法时,注入不一样的数据源,从而实现切换,即利用aop,而aop的实现是用代理实现的java
1,给工程添加一个获取数据源的路由,并给它两个不一样的数据源ide
@Bean public ThreadLocalRountingDataSource threadLocalRountingDataSource() { ThreadLocalRountingDataSource dataSource=new ThreadLocalRountingDataSource(); Map<Object, Object> targetDataSources=new HashMap<Object, Object>(); DataSource master = master();//master 数据源 DataSource slave = slave();//slave 数据源 targetDataSources.put(DataSources.MASTER, master); targetDataSources.put(DataSources.SLAVE, slave); dataSource.setTargetDataSources(targetDataSources); dataSource.setDefaultTargetDataSource(master); return dataSource; }
2,ThreadLocalRountingDataSource类主要是有一个决定数据源键的方法工具
public class ThreadLocalRountingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceTypeManager.get(); } }
3,DataSourceTypeManager实际是一个对ThreadLocal调用的一个工具类,主要是给当前线程设置期数据源的路由键,代码以下:线程
import com.example.demo.enums.DataSources; public class DataSourceTypeManager { private static final ThreadLocal<DataSources> dataSourceTypes = new ThreadLocal<DataSources>(){ @Override protected DataSources initialValue(){ return DataSources.MASTER; } }; public static DataSources get(){ return dataSourceTypes.get(); } public static void set(DataSources dataSourceType){ dataSourceTypes.set(dataSourceType); } public static void reset(){ dataSourceTypes.set(DataSources.MASTER); } }
4,编写一个aop类,决定在哪一个方法须要切换数据源代理
@Aspect // for aop @Component // for auto scan @Order(0) // execute before @Transactional public class DataSourceInterceptor { @Pointcut("execution(public * com.example.demo.service..*.getUser(..))") public void dataSourceSlave(){}; @Before("dataSourceSlave()") public void before(JoinPoint jp) { DataSourceTypeManager.set(DataSources.SLAVE); } }
彩蛋:code
事务拦截器在啥时候注入了ioc容器?blog
观察@EnableTransactionManagement,它import了 TransactionManagementConfigurationSelector类,而后给容器注入了事务
AutoProxyRegistrar和ProxyTransactionManagementConfiguration,这里咱们重点关注第二个类,点进去发现以下代码路由
给@Transactional标注的方法添加了 TransactionInterceptor 拦截器get