spring配置管理多數據源,方便服務訪問不同數據庫時,數據源切換。多少無意,直接上代碼。
1.定義數據源key枚舉值(可以直接使用字符串代替,為了代碼的整潔及易讀性,這里使用枚舉)
public enum DataSourceEnum { anquan, publ, tlshow, }
2.定義數據源持有者,切換數據源使用
public final class DataSourceHolder { private static ThreadLocal<DataSourceEnum> currentDBName = new ThreadLocal<DataSourceEnum>(); private static DataSourceEnum DEFAULT_HASH = DataSourceEnum.anquan; public static DataSourceEnum determineDefault() { return determineDS(DEFAULT_HASH); } public static DataSourceEnum determineDS(DataSourceEnum key) { currentDBName.set(key); log.debug("determineDS:" + key); return key; } public static DataSourceEnum getCurrentDBName() { return currentDBName.get(); } }
3.實現數據源路由接口
public class DBRoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getCurrentDBName(); } @Override public void setTargetDataSources(Map targetDataSources) { super.setTargetDataSources(targetDataSources); } @Override public Object unwrap(Class iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class iface) throws SQLException { return false; } }
4.定義spring 切面,在執行service方法前,切換數據源。(首先要保證spring支持注解)
@Aspect @lombok.extern.log4j.Log4j public class DetermineAspect { @Pointcut("within(com.changyou.*.service.impl.*)") public void withController() {} @Before("withController()") public void beforeAdvice(JoinPoint jp) { if(log.isDebugEnabled()) { log.debug("Reset db router before " + jp.getSignature().getDeclaringType().getSimpleName() + "." + jp.getSignature().getName() + "()"); } DataSourceMethod datasourceMethod = ((MethodSignature)jp.getSignature()).getMethod().getAnnotation(DataSourceMethod.class); DataSourceFile datasourceFile = ((MethodSignature)jp.getSignature()).getMethod().getDeclaringClass().getAnnotation(DataSourceFile.class); if(datasourceMethod!=null){ DataSourceHolder.determineDS(datasourceMethod.value()); }else if(datasourceFile!=null){ DataSourceHolder.determineDS(datasourceFile.value()); }else{ DataSourceHolder.determineDefault(); } } }
5.spring配置數據源,使用自己實現的數據源路由類(DBRoutingDataSource )
<!-- 配置數據源 -->
<bean name="dataSource_0" parent="abstractProxoolDataSource">
<property name="url" value="${jdbc.0.url}" />
<property name="username" value="${jdbc.0.username}" />
<property name="password" value="${jdbc.0.password}" />
</bean>
<!-- 配置數據源tlshow-->
<bean name="dataSource_1" parent="abstractProxoolDataSource">
<property name="url" value="${jdbc.1.url}" />
<property name="username" value="${jdbc.1.username}" />
<property name="password" value="${jdbc.1.password}" />
</bean>
<!-- 配置數據源publicaccount-->
<bean name="dataSource_2" parent="abstractProxoolDataSource">
<property name="url" value="${jdbc.2.url}" />
<property name="username" value="${jdbc.2.username}" />
<property name="password" value="${jdbc.2.password}" />
</bean>
<bean id="dataSource" class="com.changyou.common.util.dbaccess.DBRoutingDataSource">
<property name="defaultTargetDataSource" ref="dataSource_0"/>
<property name="targetDataSources">
<map key-type="com.changyou.common.enums.DataSourceEnum"><!-- 數據源枚舉 -->
<entry key="anquan" value-ref="dataSource_0" />
<entry key="tlshow" value-ref="dataSource_1" />
<entry key="publ" value-ref="dataSource_2" />
</map>
</property>
</bean>
6.基礎工作完成,下面開始使用,需要在server類或方法上添加注解。(上面的切面會查看是否有指定注解的存在)。
定義自己的注解:
@Target(value={ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSourceRouter { public DataSourceEnum value() default DataSourceEnum.anquan; }
7.開始愉快的使用吧,方法上的注解權限高於整個類上的注解,這取決於切面的處理方式。
@Service @DataSourceRouter(DataSourceEnum.publ) public class CyjUserServiceImpl{ @Autowired private UserMapper userMapper; public void saveOrUpdateBlock(CyjUserBlock cyjUserBlock) { userMapper.saveOrUpdateBlock(cyjUserBlock); } @DataSourceRouter(DataSourceEnum.anquan) public void deleteBlockById(int blockId) { userMapper.deleteBlockById(blockId); } }
ok,后期補上demo。。。。。。。