一、用例场景
对于设计复杂业务系统,往往需要接入不同渠道的数据源作为基础数据源datasource,如何在项目中很好的简便扩展数据源模块配置呢?通过spring的AbstractRoutingDataSource继承实现自定义多数据数据源的规范类如CustomerRoutingDataSource,然后通过spring的配置多数据源注册对象到CustomerRoutingDataSource来进行统一路由调度。
二、示例内容
1. Spring配置数据源效果如下,配置数据源dataSourceA、dataSourceB
<?xml version="1.0" encoding="UTF-8"?>@b@<beans xmlns="http://www.springframework.org/schema/beans"@b@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"@b@ xmlns:aop="http://www.springframework.org/schema/aop"@b@ xmlns:tx="http://www.springframework.org/schema/tx"@b@ xmlns:context="http://www.springframework.org/schema/context"@b@ xsi:schemaLocation=" @b@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd@b@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd@b@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd@b@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> @b@ @b@ <context:property-placeholder location="classpath:db.properties "/>@b@ @b@ <!-- DataSource1 proxool Configure -->@b@ <bean id="dataSourceA" class="org.logicalcobwebs.proxool.ProxoolDataSource" > @b@ <property name="driver"><value>${jdbc.driver}</value></property>@b@ <property name="driverUrl"><value>${jdbc.url}</value></property>@b@ <property name="user"><value>${jdbc.username}</value></property>@b@ <property name="password"><value>${jdbc.password}</value></property>@b@ <property name="alias"><value>${jdbc.username}</value></property>@b@ <property name="maximumActiveTime" value="3600000"/> @b@ <property name="prototypeCount" value="5"/>@b@ <property name="maximumConnectionCount" value="150"/>@b@ <property name="minimumConnectionCount" value="2"/>@b@ <property name="trace" value="true"/>@b@ <property name="verbose" value="true"/>@b@ <property name="statistics" value="30s,15m"/>@b@ <property name="simultaneousBuildThrottle" value="30"/>@b@ </bean>@b@ @b@ <!-- DataSource2 proxool Configure -->@b@ <bean id="dataSourceB" class="org.logicalcobwebs.proxool.ProxoolDataSource" > @b@ <property name="driver"><value>${jdbc2.driver}</value></property>@b@ <property name="driverUrl"><value>${jdbc2.url}</value></property>@b@ <property name="user"><value>${jdbc2.username}</value></property>@b@ <property name="password"><value>${jdbc2.password}</value></property>@b@ <property name="alias"><value>${jdbc2.username}</value></property>@b@ <property name="maximumActiveTime" value="3600000"/> @b@ <property name="prototypeCount" value="5"/>@b@ <property name="maximumConnectionCount" value="150"/>@b@ <property name="minimumConnectionCount" value="2"/>@b@ <property name="trace" value="true"/>@b@ <property name="verbose" value="true"/>@b@ <property name="statistics" value="30s,15m"/>@b@ <property name="simultaneousBuildThrottle" value="30"/>@b@ </bean>@b@ @b@ @b@ <bean id="dataSource" class="com.xwood.datasource.CustomerRoutingDataSource">@b@ <property name="targetDataSources">@b@ <map key-type="java.lang.String">@b@ <entry key="dataSource" value-ref="dataSourceA" />@b@ <entry key="dataSource2" value-ref="dataSourceB" />@b@ </map>@b@ </property>@b@ <property name="defaultTargetDataSource" ref="dataSourceA" />@b@ </bean>@b@ @b@ <bean class="com.xwood.datasource.RoutingDataSourceAspect"/>@b@ @b@ <!-- Hibernate Configure -->@b@ <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">@b@ <property name="dataSource">@b@ <ref local="dataSource"/>@b@ </property>@b@ <property name="hibernateProperties">@b@ <props>@b@ <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>@b@ <prop key="hibernate.dialect">${hibernate.dialect}</prop>@b@ <prop key="hibernate.cache.use_query_cache">true</prop>@b@ <prop key="hibernate.cache.use_second_level_cache">true</prop>@b@ <prop key="hibernate.show_sql">true</prop>@b@ <prop key="hibernate.format_sql">false</prop>@b@ <prop key="hibernate.jdbc.fetch_size">50</prop>@b@ <prop key="hibernate.jdbc.batch_size">30</prop>@b@ <prop key="hibernate.search.autoregister_listeners">false</prop>@b@ <prop key="hibernate.query.factory_class">org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory</prop>@b@ </props>@b@ </property> @b@ <property name="packagesToScan">@b@ <list> @b@ <value>com.xwood.root.model</value> @b@ </list>@b@ </property>@b@ </bean> @b@ @b@ @b@ <aop:aspectj-autoproxy />@b@ @b@</beans>
2. 自定义用户数据源路由类CustomerRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;@b@@b@public class CustomerRoutingDataSource extends AbstractRoutingDataSource {@b@@b@ protected Object determineCurrentLookupKey()@b@ {@b@ String dsType = CustomerDataSourceContextHolder.getCustomerType();@b@ return dsType;@b@ }@b@@b@}
CustomerDataSourceContextHolder解析原子类
public class CustomerDataSourceContextHolder {@b@ @b@ public static final String DATA_SOURCE_A = "dataSource"; @b@ @b@ public static final String DATA_SOURCE_B = "dataSource2"; @b@ @b@ private static final ThreadLocalcontextHolder = new ThreadLocal(); @b@ @b@ public static void setCustomerType(String customerType) { @b@ contextHolder.set(customerType); @b@ }@b@ @b@ public static String getCustomerType() { @b@ return contextHolder.get(); @b@ } @b@ @b@ public static void clearCustomerType() { @b@ contextHolder.remove(); @b@ } @b@@b@}
3. 初始化解析RoutingDataSourceAspect及RoutingDataSource辅助类
import org.aspectj.lang.annotation.Before;@b@import org.springframework.core.Ordered;@b@ @b@public class RoutingDataSourceAspect implements Ordered {@b@ @b@ public int getOrder()@b@ {@b@ return 199;@b@ }@b@@b@ @Before("execution(@org.xwood.datasource.RoutingDataSource * * (..))&& @annotation(routingDataSource)")@b@ public void route(RoutingDataSource routingDataSource) {@b@ String key = routingDataSource.key();@b@ CustomerDataSourceContextHolder.setCustomerType(key);@b@ }@b@@b@}
RoutingDataSource自定义annotation
import java.lang.annotation.Documented;@b@import java.lang.annotation.Retention;@b@import java.lang.annotation.RetentionPolicy;@b@import java.lang.annotation.Target;@b@@b@@Retention(RetentionPolicy.RUNTIME)@b@@Target({java.lang.annotation.ElementType.METHOD})@b@@Documented@b@public @interface RoutingDataSource@b@{@b@ public abstract String key();@b@}