ssm aop+注解实现多数据源随笔

1.配置数据源本地线程类

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource  extends AbstractRoutingDataSource {
	private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();

	public static void setDataSourceKey(String dataSource){
	dataSourceKey.set(dataSource);
	}

	@Override
	protected Object determineCurrentLookupKey() {
	return dataSourceKey.get();
	}
}

2.配置数据源注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
  * 定义DataSwitch的注解
  */

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface DataSwitch {
	
	String dataSource() default "";
	
}

 

3.配置aop代理切换线程池类


import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

public class DataSourceAspect{
	
	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(DataSwitch.class)) {
            	DataSwitch source = clazz.getAnnotation(DataSwitch.class);
                DynamicDataSource.setDataSourceKey(source.dataSource());
            }
            // 方法注解可以覆盖类型注解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSwitch.class)) {
            	DataSwitch source = m.getAnnotation(DataSwitch.class);
            	DynamicDataSource.setDataSourceKey(source.dataSource());
            }
        } catch (Exception e) {
            System.out.println(clazz + ":" + e.getMessage());
        }
    }
}

 

4.配置spring-context.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:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
	http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
	http://www.springframework.org/schema/task
	http://www.springframework.org/schema/task/spring-task-3.1.xsd
		http://www.springframework.org/schema/cache 
 	http://www.springframework.org/schema/cache/spring-cache.xsd"
	default-lazy-init="true">
	
	<!-- 开启注解配置 -->
    <context:annotation-config />
	<!-- 数据源配置开始 -->
	<!-- 数据源1 -->
    <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${jdbc1.url}"/>
        <property name="username" value="${jdbc1.username}"/>
        <property name="password" value="${jdbc1.password}"/>
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${druid.initialSize}"/>
        <property name="minIdle" value="${druid.minIdle}"/>
        <property name="maxActive" value="${druid.maxActive}"/>
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="${druid.maxWait}"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
        <property name="validationQuery" value="${druid.validationQuery}" />
        <property name="testWhileIdle" value="${druid.testWhileIdle}" />
        <property name="testOnBorrow" value="${druid.testOnBorrow}" />
        <property name="testOnReturn" value="${druid.testOnReturn}" />
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小  如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。-->
        <property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="${druid.maxPoolPreparedStatementPerConnectionSize}" />
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="${druid.filters}" />
        <!-- 配置公用监控数据 -->
        <property name="useGloalDataSourceStat" value="${druid.useGloalDataSourceStat}" />
        <!-- 打开removeAbandoned功能 -->
	<property name="removeAbandoned" value="${druid.removeAbandoned}" />
	<!-- 1800秒,也就是30分钟 -->
	<property name="removeAbandonedTimeout" value="${druid.removeAbandonedTimeout}" 	
	<!-- 关闭abanded连接时输出错误日志 -->
	<property name="logAbandoned" value="${druid.logAbandoned}" />
    </bean>
    
	<!-- 数据源2 -->
    <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${jdbc2.url}"/>
        <property name="username" value="${jdbc2.username}"/>
        <property name="password" value="${jdbc2.password}"/>
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${druid.initialSize}"/>
        <property name="minIdle" value="${druid.minIdle}"/>
        <property name="maxActive" value="${druid.maxActive}"/>
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="${druid.maxWait}"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
        <property name="validationQuery" value="${druid.validationQuery}" />
        <property name="testWhileIdle" value="${druid.testWhileIdle}" />
        <property name="testOnBorrow" value="${druid.testOnBorrow}" />
        <property name="testOnReturn" value="${druid.testOnReturn}" />
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小  如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。-->
        <property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="${druid.maxPoolPreparedStatementPerConnectionSize}" />
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="${druid.filters}" />
        <!-- 配置公用监控数据 -->
        <property name="useGloalDataSourceStat" value="${druid.useGloalDataSourceStat}" />
        <!-- 打开removeAbandoned功能 -->
	<property name="removeAbandoned" value="${druid.removeAbandoned}" />
	<!-- 1800秒,也就是30分钟 -->
	<property name="removeAbandonedTimeout" value="${druid.removeAbandonedTimeout}" 	
	<!-- 关闭abanded连接时输出错误日志 -->
	<property name="logAbandoned" value="${druid.logAbandoned}" />
    </bean>
    
	<!-- 配置动态数据源 -->
    <bean id="dynamicDataSource" class="com.common.DynamicDataSource" >  
        <property name="targetDataSources">  
            <map key-type="java.lang.String">  
                <!--通过不同的key决定用哪个dataSource-->  
                <entry key="dataSource1" value-ref="dataSource1"></entry>  
                <entry key="dataSource2" value-ref="dataSource2" ></entry>  
            </map>  
        </property>  
        <!--设置默认的dataSource-->  
        <property name="defaultTargetDataSource" ref="dataSource1"></property>  
    </bean>

	<!-- 配置SqlSessionFactoryBean 加载model包-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dynamicDataSource" />
	<property name="configLocation" value="classpath:spring/mybatis-config.xml" />
	<property name="typeAliasesPackage" value="com.model" />
	<property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/>
    </bean>

	<!--配置事务管理 -->
    <bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dynamicDataSource" />
    </bean>

	<!-- 开启事务注解驱动 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
	<!-- 为spring容器中配置@aspectJ切面的bean创建代理 -->
	<aop:aspectj-autoproxy proxy-target-class="true" /> 
	<!-- 配置事务的传播特性,为空,未配置 --> 
	<tx:advice id="txAdvice" transaction-manager="transactionManager" />
	<!-- 定义好的切面类 -->
	<bean id="dataSourceAspect" class="com.common.DataSourceAspect" />
	<!-- 划重点!切面的执行 -->
    <aop:config>
        <aop:aspect ref="dataSourceAspect" >
            <!-- 拦截所有service方法 -->
            <!--这里是在service上面加的注解,可自行调换,比如(execution(* com.controller..*.*(..))
)  -->
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.service.impl..*.*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
        </aop:aspect>
    </aop:config> 
	
	<!-- 自动扫描映射器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <property name="basePackage" value="com.dao" />               
    </bean>         
</beans>

5.使用,在service的方法上添加刚刚创建的数据源注解

@Service("demoService")
public class DemoService implements IDemoService{
	
	@Resource
        DemoDao demoDao;

	@Override
	public List getA() {
		return demoDao.getA();
	}

        //getB方法即可调用datasource2数据源
        @Override
        @DataSwitch(dataSource="dataSource2")
	public List getB() {
		return demoDao.getB();
	}

}

 

注:关于properties配置文件未贴出。大功告成!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值