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());  
        }  
    }  
}

 

posted on 2018-01-29 10:20  黎孟阳  阅读(244)  评论(0)    收藏  举报

导航