spring多数据源
本章接着前面内容,配置了多数据源。
application.xml内容如下:
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 以下 validator ConversionService 在使用 mvc:annotation-driven 会 自动注册--> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> </bean> <!-- 引入jdbc配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:properties/*.properties</value> <!--要是有多个配置文件,只需在这里继续添加即可 --> </list> </property> </bean> <!-- 扫描注解Bean --> <context:component-scan base-package="com.ngt.*"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 激活annotation功能 --> <context:annotation-config /> <!-- 激活annotation功能 --> <context:spring-configured /> <!-- 注解事务配置 --> <!-- 类型转换及数据格式化 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"/> <!-- 数据源1 --> <bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <!-- 不使用properties来配置 --> <!-- <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/learning" /> <property name="username" value="root" /> <property name="password" value="christmas258@" /> --> <!-- 使用properties来配置 --> <property name="driverClassName"> <value>${jdbc_driverClassName}</value> </property> <property name="url"> <value>${jdbc_url}</value> </property> <property name="username"> <value>${jdbc_username}</value> </property> <property name="password"> <value>${jdbc_password}</value> </property> </bean> <!-- 数据源2 --> <bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>${jdbc2_driverClassName}</value> </property> <property name="url"> <value>${jdbc2_url}</value> </property> <property name="username"> <value>${jdbc2_username}</value> </property> <property name="password"> <value>${jdbc2_password}</value> </property> </bean> <!-- 多数据源配置 --> <bean id="dynamicDataSource" class="com.ngt.source.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <!-- 指定lookupKey和与之对应的数据源 --> <entry key="dataSource1" value-ref="dataSource1"></entry> <entry key="dataSource2" value-ref="dataSource2"></entry> </map> </property> <!-- 这里可以指定默认的数据源 --> <property name="defaultTargetDataSource" ref="dataSource1" /> </bean> <!-- 自动扫描了所有的XxxxMapper.xml对应的mapper接口文件,这样就不用一个一个手动配置Mpper的映射了,只要Mapper接口类和Mapper映射文件对应起来就可以了。 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.ngt.*" /> </bean> <!-- 配置Mybatis的文件 ,mapperLocations配置**Mapper.xml文件位置,configLocation配置mybatis-config文件位置--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource" /> <property name="mapperLocations" value="classpath:mapper/**/*.xml"/> <property name="configLocation" value="classpath:mybatis/mybatis-config.xml" /> </bean> <bean id="dataSourceAspect" class="com.ngt.source.DataSourceAspect" /> <aop:config> <aop:aspect ref="dataSourceAspect"> <!-- 拦截所有service方法 --> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.ngt.service.impl.*.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config> <import resource="redis-config.xml"/> <bean id="redisUtils" class="com.ngt.service.RedisUtils"></bean> <import resource="/dubbo-provider.xml"/> </beans>
添加DynamicDataSourceHolder类:
package com.ngt.source; public class DynamicDataSourceHolder { /** * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰 */ private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>(); /** * * 创 建 人: * 创建时间: * 方法描述: 获取数据源 * @return */ public static String DynamicDataSource() { return THREAD_DATA_SOURCE.get(); } public static void setDataSource(String dataSource){ THREAD_DATA_SOURCE.set(dataSource); } /** * * 创 建 人: * 创建时间: * 方法描述:删除当前数据源 */ public static void clearDataSource(){ THREAD_DATA_SOURCE.remove(); } }
DynamicDataSource类继承AbstractRoutingDataSource类:
package com.ngt.source; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceHolder.DynamicDataSource(); } }
切换数据源时只需要在调用dao之前
DynamicDataSourceHolder.setDataSource("数据源标识");
或用注解来切换数据源
添加DataSource注解: 在service上用@dataSource("数据源标识") 或者service方法上,方法上的@dataSource会覆盖类上的注解。
package com.ngt.source; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value(); }
DataSourceAspect:在application.xml中配置拦截service
package com.ngt.source; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; 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(); // 默认使用目标类型的注解,如果没有则使用其实现接口的注解 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()); } } }
浙公网安备 33010602011771号