AOP获取方法注解实现动态切换数据源(以下方式尚未经过测试,仅提供思路)

------

自定义一个用于切换数据源的注解:

package com.xxx.annotation;

import org.springframework.stereotype.Component;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface DataSource {
String value() default ""; }

定义一个工具类,方便设置、删除、获取从数据源注解中得到的不同数据源类型:

package com.xxx.utils.dataSource;

public class DataSourceHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

    /**
* @Description: 设置数据源类型
* @param dataSourceType 数据库类型
* @return void
* @throws
*/
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
} /**
* @Description: 获取数据源类型
* @param
* @return String
* @throws
*/
public static String getDataSourceType() {
return contextHolder.get();
} /**
* @Description: 清除数据源类型
* @param
* @return void
* @throws
*/
public static void clearDataSourceType() {
contextHolder.remove();
}
}

--------

配置动态数据源:

spring配置文件:

<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd
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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<!-- 引入配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties" />
</bean> <bean id="dataSource_R" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name ="jndiName">
<!-- 下面第一行为测试环境配置,第二行为生产环境配置,运行时保留一个 -->
<value>java:comp/env/jdbc/JTORDER</value>
<!-- <value>jdbc/JTORDER</value> -->
</property>
</bean> <bean id="dataSource_RW" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name ="jndiName">
<!-- 下面第一行为测试环境配置,第二行为生产环境配置,运行时保留一个 -->
<value>java:comp/env/jdbc/JTORDER</value>
<!-- <value>jdbc/JTORDER</value> -->
</property>
</bean> <!-- 动态数据源 -->
<bean id="dataSource" class="com.xxx.utils.dataSource.RoutingDataSource">
<!-- 为targetDataSources注入两个数据源 -->
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="R" value-ref="dataSource_R"/>
<entry key="RW" value-ref="dataSource_RW"/>
</map>
</property>
<!-- 为指定数据源RoutingDataSource注入默认的数据源-->
<property name="defaultTargetDataSource" ref="dataSource_R"/>
</bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<!--<property name="mapperLocations" value="classpath:mapping/*.xml"></property>-->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<property name="mapperLocations" value="classpath*:module.*.mapper/*.xml"></property>
</bean> <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <!-- xml接口映射文件 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xxx.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean> <!-- 配置事物切点 -->
<aop:config>
<aop:pointcut id="transactionPointcut" expression="execution(* com.xxx.service.impl.*.*(..) )"/>
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
</aop:config> <!-- 注解方式配置事务-->
<!-- <tx:annotation-driven transaction-manager="transactionManager" /> --> <!-- 拦截器方式配置事务-->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice> <!-- 自动扫描定时任务 -->
<task:annotation-driven/>
<!-- spring自动创建代理,植入切面,proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy
poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。 -->
<aop:aspectj-autoproxy proxy-target-class="true"/> </beans> <!--
本地测试需要在Tomcat的context.xml的 <Context> 标签中加入如下配置:
<Resource
name="jdbc/myName1"
scope="Shareable"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
url="jdbc:oracle:thin:@10.10.10.10:1521:xxdb1"
driverClassName ="oracle.jdbc.driver.OracleDriver"
username="usesr1"
password="pwd1"
/> <Resource
name="jdbc/myName2"
scope="Shareable"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
url="jdbc:oracle:thin:@10.10.10.10:1521:xxdb2"
driverClassName ="oracle.jdbc.driver.OracleDriver"
username="user2"
password="pwd2"
/> -->

动态数据源类【其中RoutingDataSource 和上面xml中的RoutingDataSource 对应】:

package com.xxx.utils.dataSource;

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

public class RoutingDataSource extends AbstractRoutingDataSource {

    @Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSourceType();
}
}

它的作用是通过获取我们自定义的数据源类型持有工具类DataSourceHolder中存储的数据源类型来动态试用真正的数据源

--------

通过AOP获取方法上的注解实现动态切换数据源

(其中@Order(1)作用:

Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟spring的事务aop执行的先后顺序问题,比如说动态切换数据源的问题,如果事务在前,数据源切换在后,会导致数据源切换失效,所以就用到了Order(排序)这个关键字.)

import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Repository; @Order(1)
@Aspect
@Repository
public class DataSourceAspect { @Pointcut("execution(* com.xxx.service.impl.*.*(..))")
private void anyMethod() {} @AfterReturning(value = "anyMethod()", returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
DataSourceHolder.clearDataSourceType();
} @Before(value="anyMethod()")
public void before(JoinPoint joinPoint){
     //通过切点对象获取当前切点所在的方法对象
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
//如果方法体上使用了DataSource注解
if (method.isAnnotationPresent(DataSource.class)) {
//获取该方法上的注解名
DataSource datasource = method.getAnnotation(DataSource.class);
//将方法体上的注解的值赋予给DataSourceHolder数据源持有类
DataSourceHolder.setDataSourceType(datasource.value());
}
}
}

试用时只需要在被切方法上加上自定义注解,并且在里面配上不同的目标数据源即可。

AOP获取方法注解实现动态切换数据源的更多相关文章

  1. 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法

    相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...

  2. Spring+Mybatis动态切换数据源

    功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...

  3. Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  4. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  5. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  6. SSM动态切换数据源

    有需求就要想办法解决,最近参与的项目其涉及的三个数据表分别在三台不同的服务器上,这就有点突兀了,第一次遇到这种情况,可这难不倒笔者,资料一查,代码一打,回头看看源码,万事大吉 1. 预备知识 这里默认 ...

  7. 基于AbstractRoutingDataSource实现动态切换数据源

    基于AbstractRoutingDataSource实现动态切换数据源 /**  * DataSource注解接口  */ @Target({ElementType.TYPE, ElementTyp ...

  8. Spring动态切换数据源及事务

    前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...

  9. Spring Boot 如何动态切换数据源

    本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...

随机推荐

  1. 学习笔记:安装swig+用SWIG封装C++为Python模块+SWIG使用说明

    这段时间一直在摸索swing,用它来封装C++代码来生成python脚步语言.并总结了swing从安装到配置再到代码封装编译生成动态库的整个过程,下面这篇文章都是我在实际的运用中的一些经验总结,分享给 ...

  2. JSON添加注释的问题

    JSON有两种数据结构: 名称/值对的集合:key : value样式: 值的有序列表:就是Array: 而在JSON的文档中说明只要是不符合上面两种结构的都不被支持,并提示错误 添加注释//或者/* ...

  3. CSS 中用户自定义字体 @font-face

    @font-face 允许网页中使用自定义的字体,这些自定义的字体被放置在服务器上,从而让网页摆脱对访问者计算机上字体环境的依赖. 简单的说,有了@font-face,只需将字体上传到服务器端,无论访 ...

  4. php函数copy和rename的区别

    copy ( string source, string dest )将文件从 source 拷贝到 dest.如果成功则返回 TRUE,失败则返回 FALSE. 如果要移动文件的话,请用 renam ...

  5. thymeleaf小知识

    1.根据不同性别,显明不同的默认图片:th:if th:src   图片路径 <img th:if="${gender=='男'}" id="admission_p ...

  6. 鼠标点击自定义文字展现特效JS代码

    JS特效使用方法 只需将如下JS代码放到</body>之前就好了 var a_idx = 0; jQuery(document).ready(function($) { $("b ...

  7. linux基础_使用指令

    1.指令运行级别 (0)关机 (1)单用户(找回丢失密码) (2)多用户无网络服务 (3)多用户有网络服务 (4)保留 (5)图形界面 (6)重启 /etc/inittab:系统的运行级别配置之文件 ...

  8. iOS native plugin 的代码sample

    https://bitbucket.org/Unity-Technologies/iosnativecodesamples/src/stable/ 不在这个stable版本 在2017 dev这个版本

  9. oracle之函数-数字,日期,转换,字符串,其他

    -----------------------------oracle数据库函数----------------------------------------数学函数***select abs(-1 ...

  10. springboot 详解RestControllerAdvice(ControllerAdvice)(转)

    springboot 详解RestControllerAdvice(ControllerAdvice)拦截异常并统一处理简介 @Target({ElementType.TYPE}) @Retentio ...