`

<转>Spring AOP根据JdbcTemplate方法名动态设置数据源

 
阅读更多

转载: Spring AOP根据JdbcTemplate方法名动态设置数据源

http://blog.csdn.net/yubaoma2014/article/details/12427885
作者: yubaoma2014

 

有删节.

 

目的: 

1. 配置多个数据源

2. 根据不同的数据源执行不同的数据操作方法

3. 事务管理?

 

  • 多数据源配置
        <!-- 主数据源, 用于执行写入操作 -->
        <bean id="masterDataSource"
            class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
            <property name="driverClassName"
                value="${jdbc.driverClassName}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
            <property name="poolPreparedStatements" value="true" />
            <property name="defaultAutoCommit" value="true" />
        </bean>
        <!-- 从数据源, 用于执行查询操作 -->
        <bean id="slaveDataSource"
            class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
            <property name="driverClassName"
                value="${jdbc.driverClassName}" />
            <property name="url" value="${jdbc.url2}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
            <property name="poolPreparedStatements" value="true" />
            <property name="defaultAutoCommit" value="true" />
        </bean>
    
        <!-- 动态数据源 -->
        <bean id="dataSource"
            class="test.my.serivce.ds.DynamicDataSource">
            <!-- 配置一个数据源Map, 注意这里的key值, 后面很多地方都使用到 -->
            <property name="targetDataSources">
                <map>
                    <entry key="master" value-ref="masterDataSource" />
                    <entry key="slave" value-ref="slaveDataSource" />
                </map>
            </property>
            <!-- 动态数据源默认使用的数据源 -->
            <property name="defaultTargetDataSource" ref="masterDataSource" />
        </bean>
    
    <!-- 配置JdbcTemplate -->
    <bean id="jdbcTemplate"
            class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
    BEAN "dataSource" 是自定义类DynamicDataSource的一个实例, 而DynamicDataSource则是继承了Spring的抽象类AbstractRoutingDataSource, 顾名思义, 这是一个数据源的路由/查找类.
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    // 自定义类
    public class DynamicDataSource extends AbstractRoutingDataSource {
        
        @Override
        // 返回当前需要使用的数据源的key
        protected Object determineCurrentLookupKey() {
            // 
            return CustomerContextHolder.getCustomerType();
        }
    }
     
    //  AbstractRoutingDataSource 的部分源码
    
    public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
            
            // 重写了 getConnection() 方法
         	@Override
    	public Connection getConnection() throws SQLException {
    		return determineTargetDataSource().getConnection();
    	}
    
            // 设置当前使用的目标数据源
    	protected DataSource determineTargetDataSource() {
    		Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
                    // 目标数据源的key.
    		Object lookupKey = determineCurrentLookupKey();
                    // 获取数据源
    		DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    		if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
    			dataSource = this.resolvedDefaultDataSource;
    		}
    		if (dataSource == null) {
    			throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    		}
    		return dataSource;
    	}
            
            // 抽象方法, 返回目标数据源对应的key
            // 这里的key对应于在BEAN "dataSource"中配置的属性"targetDataSources"中的key
            protected abstract Object determineCurrentLookupKey();
    }
     
    // CustomerContextHolder, 一个ThreadLocal实现, 用于管理key
    // ThreadLocal是线程安全的, 且线程之间不能共享
    public class CustomerContextHolder {
        private static final ThreadLocal contextHolder = new ThreadLocal();
        public static void setCustomerType(String customerType) {
            contextHolder.set(customerType);
        }
        public static String getCustomerType() {
            return (String) contextHolder.get();
        }
        public static void clearCustomerType() {
            contextHolder.remove();
        }
    }
     
  • 利用AOP, 实现不同的数据源执行不同的数据操作方法
        <bean id="ba" class="test.my.serivce.ds.BeforeAdvice" />
        <!-- 强制使用CGLIB代理 -->
        <aop:config proxy-target-class="true">
    
            <!-- 切面一 主数据源执行写入操作 -->
            <aop:aspect ref="ba">
                <!-- 切点, 与数据库update相关的函数 -->
                <aop:pointcut id="update"
                    expression="execution(* org.springframework.jdbc.core.JdbcTemplate.update*(..)) || execution(* org.springframework.jdbc.core.JdbcTemplate.batchUpdate(..))" />
                <!-- 前置通知, 执行数据源设置操作 -->
                <aop:before method="setMasterDataSource"
                    pointcut-ref="update" />
            </aop:aspect>
    
            <!-- 切面二 从数据源执行查询操作 -->
            <aop:aspect ref="ba">
                <aop:before method="setSlaveDataSource"
                    pointcut="execution(* org.springframework.jdbc.core.JdbcTemplate.query*(..)) || execution(* org.springframework.jdbc.core.JdbcTemplate.execute(..))" />
            </aop:aspect>
        </aop:config>
        
     BEAN "ba"相关的类
    public class BeforeAdvice {
        public void setMasterDataSource() {
            CustomerContextHolder.setCustomerType("master");
        }
        public void setSlaveDataSource() {
            CustomerContextHolder.setCustomerType("slave");
        }
    }
     
分享到:
评论

相关推荐

    springAop多数据源

    spring jdbcTemplate 多数据源切换数据库操作,junit测试。

    spring applicationContext 配置文件

    &lt;?xml version="1.0" encoding="UTF-... &lt;bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"&gt; &lt;property name="dataSource"&gt;&lt;ref bean="dataSourceProxy"/&gt;&lt;/property&gt; &lt;/bean&gt; &lt;/beans&gt;

    Spring中文帮助文档

    9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知事务操作 9.5.9. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用TransactionTemplate 9.6.2. ...

    spring_in_action-sixth-edition.pdf

    Spring Data JDBC 提供了多种 JDBC 数据访问解决方案,例如使用 JdbcTemplate、使用 Spring Data JDBC 等。 15. Spring Data JPA Spring Data JPA 是指使用 Spring 框架的 JPA 数据访问层,帮助开发者快速构建数据...

    Spring入门学习笔记|Spring学习.pdf

    Spring入门学习笔记,内容包括Spring介绍,Spring配置文件,Spring配置数据源,Spring的注解开发,Spring集成Junit,Spring的AOP,jdbcTemplate介绍,Spring控制事务流程,Spring集成web。

    Spring.3.x企业应用开发实战(完整版).part2

    8.4.3 Spring的数据源实现类 8.5 小结 第9章 Spring的事务管理 9.1 数据库事务基础知识 9.1.1 何为数据库事务 9.1.2 数据并发的问题 9.1.3 数据库锁机制 9.1.4 事务隔离级别 9.1.5 JDBC对事务支持 9.2 ThreadLocal...

    SSM框架教程Spring+SpringMVC+MyBatis全覆盖_Java热门框架视频教程

    6、Spring数据源集成配置 7、Spring注解开发 8、Spring集成Junit测试 9、Spring集成web环境 10、Spring JDBCTemplate基本使用 11、SpringAOP简介和快速入门 12、Spring XML方式配置AOP 13、Spring注解方式配置AOP 14...

    Spring-Reference_zh_CN(Spring中文参考手册)

    9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 9.5.7. 插入事务操作 9.5.8. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用 ...

    Spring3.x企业应用开发实战(完整版) part1

    8.4.3 Spring的数据源实现类 8.5 小结 第9章 Spring的事务管理 9.1 数据库事务基础知识 9.1.1 何为数据库事务 9.1.2 数据并发的问题 9.1.3 数据库锁机制 9.1.4 事务隔离级别 9.1.5 JDBC对事务支持 9.2 ThreadLocal...

    Spring Boot实战与原理分析视频课程包含14-18

    --多种数据源的配置、JdbcTemplate、事务的处理 20 Spring Boot AOP 21 Spring Boot Starter18:31 --快速构建自定义的Spring Boot Starter 22 Spring Boot 日志30:58 --演示了如何在Spring Boot里面使用日志配置...

    SpringAll_wuyouzhuguli.tar.gz

    Spring Boot JdbcTemplate配置Druid多数据源 Spring Boot AOP记录用户操作日志 Spring Boot中使用thymeleaf Spring Boot中使用Redis缓存数据 Spring Boot中使用Ehcache缓存数据 Spring Boot中的JSON技术 Spring Boot...

    Spring 2.0 开发参考手册

    9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用 TransactionTemplate 9.6.2. 使用 ...

    Spring API

    9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知事务操作 9.5.9. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用TransactionTemplate 9.6.2. ...

    spring chm文档

    9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. 结合AspectJ使用 @Transactional 9.6. 编程式事务管理 9.6.1. 使用 TransactionTemplate 9.6.2. 使用 ...

    spring boot 全面的样例代码

    - chapter3-2-4:[多数据源配置(二):Spring-data-jpa](http://blog.didispace.com/springbootmultidatasource/) - chapter3-2-5:[使用NoSQL数据库(一):Redis](http://blog.didispace.com/springbootredis/) -...

    spring-boot-demo_xkcoding.tar.gz

    ElasticSearch(基本操作和高级查询)、Async(异步任务)、集成Dubbo(采用官方的starter)、MongoDB(文档数据库)、neo4j(图数据库)、docker(容器化)...第三方登录)、LDAP(增删改查)、动态添加/切换数据源、单机限流(AOP +...

    声明式事务1

    要使用声明式事务,需要先搭建环境,包括导入相关依赖、配置数据源和 JdbcTemplate、给方法上标注 @Transactional、开启基于注解的事务管理功能、配置事务管理器等步骤。 1. 导入相关依赖:需要导入 Spring-jdbc ...

    spring boot集成demo大全.zip

    ElasticSearch(`基本操作和高级查询`)、Async(`异步任务`)、集成Dubbo(`采用官方的starter`)、MongoDB(`文档数据库`)、neo4j(`图数据库`)、docker...登录`)、LDAP(`增删改查`)、`动态添加/切换数据源`、单机限流(`AOP +...

    springboot学习

    chapter3-2-4:多数据源配置(二):Spring-data-jpa chapter3-2-5:使用NoSQL数据库(一):Redis chapter3-2-6:使用NoSQL数据库(二):MongoDB chapter3-2-7:整合MyBatis chapter3-2-8:MyBatis注解配置详解 ...

    jsboot-admin:spring-boot企业项目脚手架

    Redis jwt mybatis / jdbcTemplate任选定时任务内置用户-角色-权限控制多角色免重登切换模块标签页切换免刷新AOP实现多数据源动态切换(分支:multi-datasource)运行截图说明如有任何问题欢迎在问题中讨论

Global site tag (gtag.js) - Google Analytics