使用到技術 aop 註解java
1.先看spring中Datasource類spring
public interface DataSource extends CommonDataSource,Wrapper {sql
Connection getConnection() throws SQLException;express
Connection getConnection(String username, String password) throws SQLException;apache
}tomcat
兩個方法都是獲得鏈接的。在看下AbstractRoutingDataSource是怎麼實現DataSource接口mybatis
public Connection getConnection() throws SQLException {app
return determineTargetDataSource().getConnection();ide
}字體
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
很明顯是使用determineTargetDataSource()方法獲取到的connection。determineTargetDataSource方法定義以下:
private Map<Object, DataSource> resolvedDataSources;
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}
protected abstract Object determineCurrentLookupKey();
很顯然是上面加粗字體獲得的數據源;
resolvedDataSources數據類型是map,能夠把masterDatasource 跟 slaveDatasource存到map中
而後寫一個類DynamicDataSource繼承AbstractRoutingDataSource,實現determineCurrentLookupKey()方法,該方法返回map的key,master或者slave就能夠了。
2.具體實現:
//添加註解方式
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
String value();
}
//動態獲取數據源類 繼承 AbstractRoutingDataSource 實現他裏面的抽象方法返回master或者slave
public class DynamicDataSource extends AbstractRoutingDataSource {
protected Object determineCurrentLookupKey() {
// TODO Auto-generated method stub return DynamicDataSourceHolder.getDataSouce();
}
}
//建立線程獲取註解獲得的數據源
public class DynamicDataSourceHolder {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
public static void putDataSource(String name) {
holder.set(name);
}
public static String getDataSouce() {
return holder.get();
}
}
//下面是核心部分,aop
public class DataSourceAspect {
public void before(JoinPoint point) {
Object target = point.getTarget();
String method = point.getSignature().getName();
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes=((MethodSignature) point.getSignature()) .getMethod().getParameterTypes();
try {
Method m = classz[0].getMethod(method, parameterTypes);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m .getAnnotation(DataSource.class); DynamicDataSourceHolder.putDataSource(data.value());
System.out.println(data.value());
}
}
catch (Exception e) { // TODO: handle exception } } }
// 重點 配置文件使用
<!--主數據源 能夠使用讀取jdbc -->
<!-- 數據源配置 master-->
<bean id="masterDataSource" destroy-method="close" class="org.apache.tomcat.dbcp.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver.master}" />
<property name="url" value="${jdbc.url.master}" />
<property name="username" value="${jdbc.username.master}" />
<property name="password" value="${jdbc.password.master}" />
</bean>
<!-- 數據源配置 slave-->
<bean id="slaveDataSource" destroy-method="close" class="org.apache.tomcat.dbcp.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver.slave}" />
<property name="url" value="${jdbc.url.slave}" />
<property name="username" value="${jdbc.username.slave}" />
<property name="password" value="${jdbc.password.slave}" />
</bean>
下劃線部分須要添加 xmlns:beans="http://www.springframework.org/schema/beans" 頭部空間文件 否則會報錯
<!-- 數據源的得到 -->
<beans:bean id="dataSource" class="com.rainbow.base.common.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- write -->
<entry key="master" value-ref="masterDataSource"/>
<!-- read -->
<entry key="slave" value-ref="slaveDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="masterDataSource"/>
</beans:bean>
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置AOP切面 這裏我選擇切點是service 由於service切面能夠控制好事務 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<beans:bean id="manyDataSourceAspect" class="com.rainbow.base.common.DataSourceAspect" />
<aop:config>
<aop:aspect id="c" ref="manyDataSourceAspect">
<aop:pointcut id="tx" expression="execution(* com.rainbow.*.service.*.*(..))"/>
<aop:before pointcut-ref="tx" method="before"/>
</aop:aspect>
</aop:config>
<!-- mybatis集成配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:conf/mybatis/mybatis-config.xml" />
<property name="mapperLocations">
<list>
<value>classpath*:conf/mybatis/mappers/**/*.xml</value>
</list>
</property>
</bean>