<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd "> <!-- 配置數據源 --> <bean name="datasource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc.urlmaster}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置數據源1 --> <bean name="datasource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc.urlslave}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <bean id="multipleDataSource" class="pers.aidenj.ostrich.common.DataSource.DynamicDataSource"> <property name="targetDataSources"> <map> <entry key="datasource" value-ref="datasource"/> <entry key="datasource1" value-ref="datasource1"/> </map> </property> <property name="defaultTargetDataSource" ref="datasource"/> <!-- 默認數據源 --> </bean> <!-- 配置sqlSessionFactory 並讀取mybatis的一些配置 --> <bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="multipleDataSource"></property> <property name="mapperLocations" value="classpath:pers/aidenj/ostrich/mapping/*.xml" /> </bean> <!-- 自動掃描 將Mapper接口生成代理注入到Spring --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="pers.aidenj.ostrich.mapper" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> </bean> <!-- 配置事物 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="multipleDataSource"></property> </bean> <tx:annotation-driven transaction-manager = "transactionManager"/> <!-- 事物的具體內容 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="append*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="repair" propagation="REQUIRED" /> <tx:method name="delAndRepair" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <!-- 爲業務邏輯層的方法解析@DataSource註解 爲當前線程的routeholder注入數據源key --> <bean id="dataSourceAspect" class="pers.aidenj.ostrich.common.aop.DataSourceAspect" /> <aop:config proxy-target-class="true"> <!-- 定義一個切面 --> <aop:aspect id="dataSourceAspect" ref="dataSourceAspect" order="1"> <!-- 定義一個切點 --> <aop:pointcut id="dataSourcePointcut" expression="execution(* pers.aidenj.ostrich.service.*.*(..)) "/> <!-- 前通知 --> <!-- <aop:before pointcut-ref="dataSourcePointcut" method="before" /> --> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config> </beans>
package pers.aidenj.ostrich.common.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value(); }
package pers.aidenj.ostrich.common.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; import java.lang.reflect.Method; import pers.aidenj.ostrich.common.DataSource.DynamicDataSourceHolder; import pers.aidenj.ostrich.common.annotation.DataSource; public class DataSourceAspect { /** * 攔截目標方法,獲取由@DataSource指定的數據源標識,設置到線程存儲中以便切換數據源 * * @param point * @throws Exception */ public void intercept(JoinPoint point) throws Exception { Class<?> target = point.getTarget().getClass(); MethodSignature signature = (MethodSignature) point.getSignature(); // 默認使用目標類型的註解,若是沒有則使用其實現接口的註解 signature.getMethod().getParameterTypes(); for (Class<?> clazz : target.getInterfaces()) { resolveDataSource(clazz, signature.getMethod()); } resolveDataSource(target, signature.getMethod()); } /** * 提取目標對象方法註解和類型註解中的數據源標識 * * @param clazz * @param method */ private void resolveDataSource(Class<?> clazz, Method method) { try { Class<?>[] types = method.getParameterTypes(); // 默認使用類型註解 if (clazz.isAnnotationPresent(DataSource.class)) { DataSource source = clazz.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } // 方法註解能夠覆蓋類型註解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource source = m.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } } catch (Exception e) { System.out.println(clazz + ":" + e.getMessage()); } } }
package pers.aidenj.ostrich.serviceImpl; import java.util.List; import javax.annotation.Resource; import org.springframework.stereotype.Service; import pers.aidenj.ostrich.common.DataSource.DynamicDataSourceHolder; import pers.aidenj.ostrich.common.annotation.DataSource; import pers.aidenj.ostrich.mapper.DictionaryMapper; import pers.aidenj.ostrich.model.Dictionary; import pers.aidenj.ostrich.service.DictionaryService; @Service("dictionaryService") public class DictionaryServiceImpl implements DictionaryService { @Resource DictionaryMapper dictionaryMapper; @Override public boolean getOneData() { // TODO Auto-generated method stub return true; } //沒有指定庫,使用默認 @Override public List<Dictionary> getAllDictionary() { // TODO Auto-generated method stub return dictionaryMapper.getAllDictionary(); } //指定master @Override @DataSource("datasource") public List<Dictionary> getAllDictionaryMasterDataSource() { // TODO Auto-generated method stub return dictionaryMapper.getAllDictionary(); } //指定master @Override public List<Dictionary> getAllDictionaryMaster() { // TODO Auto-generated method stub DynamicDataSourceHolder.setDataSource("datasource"); return dictionaryMapper.getAllDictionary(); } //指定slave @Override @DataSource("datasource1") public List<Dictionary> getAllDictionarySlaveDataSource() { // TODO Auto-generated method stub return dictionaryMapper.getAllDictionary(); } //指定slave @Override public List<Dictionary> getAllDictionarySlave() { // TODO Auto-generated method stub DynamicDataSourceHolder.setDataSource("datasource1"); return dictionaryMapper.getAllDictionary(); } }