AOP实现Spring多数据源操作

来源:互联网 发布:文明6 简体中文 mac版 编辑:程序博客网 时间:2024/05/21 20:28

通过继承Spring的AbstractRoutingDataSource抽象类,对 afterpropertiesset、 determineCurrentLookupKey方法重写

1、继承AbstractRoutingDataSource,重写方法

/** * 继承{@link AbstractRoutingDataSource} * @author Cheng.Wei * @ClassName DynamicDataSource * @Description  动态数据源--可根据不同的数据索引连接不同的数据库 * @date 2017-06-13 10:52 */public class DynamicDataSource extends AbstractRoutingDataSource {    private DataSource master; // 默认主库    private Map<String, DataSource> synergy; // 其他数据源,允许多个通过 key获取    private Map<Object, Object> dataSources = new HashMap<Object, Object>();    private static final String DEFAULT = DBSource.MASTER.getKey();    private static final ThreadLocal<String> datasourceHolder = new ThreadLocal<String>();    @Override    public void afterPropertiesSet() {        if (null == master) {            throw new IllegalArgumentException("'master' is required");        }        dataSources.put(DEFAULT, master);        if (null != synergy && synergy.size() > 0) {            for (Map.Entry<String, DataSource> entry : synergy.entrySet()) {                dataSources.put(entry.getKey(), entry.getValue());            }        }        this.setDefaultTargetDataSource(master);        this.setTargetDataSources(dataSources);        super.afterPropertiesSet();    }    @Override    protected Object determineCurrentLookupKey() {      return datasourceHolder.get();    }    public static void setDataSource(String dataSource)    {        datasourceHolder.set(dataSource);    }    public static void reset()    {        datasourceHolder.remove();    }    public void setMaster(DataSource master) {        this.master = master;    }    public void setSynergy(Map<String, DataSource> synergy) {        this.synergy = synergy;    }}


2、配置文件

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:tx="http://www.springframework.org/schema/tx"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"       default-lazy-init="false">    <context:component-scan base-package="com.dhweicheng">        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>    </context:component-scan>    <context:property-placeholder location="classpath:config.properties"/>    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"/>    <!-- 主库数据数据源 -->    <bean id="master-dataSource" parent="druidDataSource"          init-method="init" destroy-method="close">        <property name="url" value="${master.connection.url}"/>        <property name="username" value="${master.connection.username}"/>        <property name="password" value="${master.connection.password}"/>        <property name="initialSize" value="${master.druid.initialSize}"/>        <property name="maxActive" value="${master.druid.maxActive}"/>        <property name="minIdle" value="${master.druid.minIdle}"/>        <property name="maxWait" value="${master.druid.maxWait}"/>        <property name="poolPreparedStatements" value="${master.druid.poolPreparedStatements}"/>        <property name="maxPoolPreparedStatementPerConnectionSize" value="${master.druid.maxPoolPreparedStatementPerConnectionSize}"/>        <property name="validationQuery" value="${master.druid.validationQuery}"/>        <property name="testOnBorrow" value="${master.druid.testOnBorrow}"/>        <property name="testOnReturn" value="${master.druid.testOnReturn}"/>        <property name="testWhileIdle" value="${master.druid.testWhileIdle}"/>        <property name="timeBetweenEvictionRunsMillis" value="${master.druid.timeBetweenEvictionRunsMillis}"/>        <property name="minEvictableIdleTimeMillis" value="${master.druid.minEvictableIdleTimeMillis}"/>        <property name="removeAbandoned" value="${master.druid.removeAbandoned}"/>        <property name="removeAbandonedTimeout" value="${master.druid.removeAbandonedTimeout}"/>        <property name="logAbandoned" value="${master.druid.logAbandoned}"/>        <property name="filters" value="${master.druid.filters}"/>    </bean>    <!-- 从库数据源 -->    <bean id="yhz-dataSource" parent="druidDataSource"          init-method="init" destroy-method="close">        <property name="url" value="${yhz.connection.url}"/>        <property name="username" value="${yhz.connection.username}"/>        <property name="password" value="${yhz.connection.password}"/>        <property name="initialSize" value="${yhz.druid.initialSize}"/>        <property name="maxActive" value="${yhz.druid.maxActive}"/>        <property name="minIdle" value="${yhz.druid.minIdle}"/>        <property name="maxWait" value="${yhz.druid.maxWait}"/>        <property name="poolPreparedStatements" value="${yhz.druid.poolPreparedStatements}"/>        <property name="maxPoolPreparedStatementPerConnectionSize" value="${yhz.druid.maxPoolPreparedStatementPerConnectionSize}"/>        <property name="validationQuery" value="${yhz.druid.validationQuery}"/>        <property name="testOnBorrow" value="${yhz.druid.testOnBorrow}"/>        <property name="testOnReturn" value="${yzh.druid.testOnReturn}"/>        <property name="testWhileIdle" value="${yhz.druid.testWhileIdle}"/>        <property name="timeBetweenEvictionRunsMillis" value="${yhz.druid.timeBetweenEvictionRunsMillis}"/>        <property name="minEvictableIdleTimeMillis" value="${yhz.druid.minEvictableIdleTimeMillis}"/>        <property name="removeAbandoned" value="${yhz.druid.removeAbandoned}"/>        <property name="removeAbandonedTimeout" value="${yhz.druid.removeAbandonedTimeout}"/>        <property name="logAbandoned" value="${yhz.druid.logAbandoned}"/>        <property name="filters" value="${yhz.druid.filters}"/>    </bean>    <!--主从库选择-->    <bean id="dynamicDataSource" class="com.dhweicheng.core.datasource.DynamicDataSource">       <property name="master" ref="master-dataSource"/>       <property name="synergy">           <map key-type="java.lang.String">               <entry key="master" value-ref="master-dataSource"/>               <entry key="yhz" value-ref="yhz-dataSource"/>           </map>       </property>    </bean>    <!-- 配置数据源 -->    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">        <property name="dataSource" ref="dynamicDataSource"/>        <property name="configLocation" value="classpath:mybatis_cfg.xml"/>        <property name="mapperLocations" value="classpath:com/dhweicheng/**/**/mapping/*.xml"/>    </bean>    <!--mybatis自动扫描加载Sql映射文件/接口 : MapperScannerConfigurer sqlSessionFactory    basePackage:指定sql映射文件/接口所在的包(自动扫描) -->    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>        <property name="basePackage" value="com.dhweicheng.web.**.mapper"/>    </bean>    <bean id="txManager"          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dynamicDataSource"/>    </bean>    <tx:annotation-driven transaction-manager="txManager"/></beans>

3、自定义注解

/** * @author Cheng.Wei * @ClassName DataSourceMapping * @Description 基于Java 注解 实现动态数据源动态选择, 默认使用主库 * @date 2017-06-13 10:47 */@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface DataSourceMapping {    DBSource value() default DBSource.MASTER;}

4、AOP切换数据源

/** * 有{@link DataSourceMapping}注解的方法,调用时会切换到指定的数据源 * @author Cheng.Wei * @ClassName DataSourceAspect * @Description 基于AOP的多数据远切换 * @date 2017-06-13 13:04 */@Component@Aspectpublic class DataSourceAspect {    @Around(value = "@annotation(com.dhweicheng.core.annotation.DataSourceMapping)", argNames = "pjp")    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {        Object val = null;        MethodSignature ms = (MethodSignature) pjp.getSignature();        Method method = ms.getMethod();        DataSourceMapping annotation = method.getAnnotation(DataSourceMapping.class);        boolean changeDataSource = false;        try {            if (null != annotation) {                changeDataSource = true;                    DynamicDataSource.setDataSource(annotation.value().getKey());            }            val = pjp.proceed();        } catch (Throwable e) {            throw e;        } finally {            if (changeDataSource) {                DynamicDataSource.reset();            }        }        return val;    }}


5、使用

@Override@DataSourceMapping(DBSource.YHZ_DATASOURCE)public Role selectByPrimaryKey(Integer id) {    return roleMapper.selectByPrimaryKey(id);}
注意配置:

   <aop:aspectj-autoproxy proxy-target-class="true"/>





原创粉丝点击