Spring Boot 声明式事务结合相关拦截器
我这项目的读写分离方式在使用ThreadLocal实现的读写分离在迁移后的偶发错误里提了,我不再说一次了,这次是有要求读写分离与事务部分要完全脱离配置文件,程序员折腾了很久,于是我就查了一下,由于我还是比较喜欢使用xml的方式,所以就随便。。。(过程省略吧),然而,似乎是一定要声明式的方式,所以,无奈之下就只好干了。
首先,在之前的博客里提到过,我们的读写分离方式要求我们自己的AOP拦截器必须在事务拦截器之前执行,在配置文件的方式下很容易,在aop的配置里设置一下Order就好了。然而,Spring Boot的@EnableTransactionManagement注解中已经把这部分固定了,官方文档似乎说它是和@Transactional配合使用的,总之几乎没有留下什么插手的余地(如果大家有好办法,希望能告诉我一下):



这个ProxyTransactionManagementConfiguration类中,就直接手new了TransactionInterceptor:
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}

虽然这里可以通过上图的方式加点什么,但这个事务体系本身是非常独立的,而且在启动过程中就已经确定下来了,既然要调节它和自定义的aop的执行顺序,我想只能先统一他们的执行策略。之前自定义的aop是在启动过程中就被加入到一个拦截器的调用链中:

由于Spring Boot很多东西并没有留什么扩展的余地(就好像前面那个new),如果完全不用配置文件,使用Spring Boot的方式,虽然没有什么顺眼的方法,其实也还是能做的,先提个建议,能不用的情况下,最好不要用。方法是自定义一个事务拦截器,抛弃@EnableTransactionManagement,测试代码如下,不要在意命名,图方便直接在原来的上面改的:
@Bean(name = "newDataSourceAop")
public NewDataSourceAop newDataSourceAop(){
return new NewDataSourceAop();
} @Bean(name = "tInterceptor")
public TInterceptor tInterceptor(){
return new TInterceptor();
} /**
* 代理
* @return
*/
@Bean
public BeanNameAutoProxyCreator transactionAutoProxy() {
BeanNameAutoProxyCreator autoProxy = new BeanNameAutoProxyCreator();
autoProxy.setProxyTargetClass(true);// 这个属性为true时,表示被代理的是目标类本身而不是目标类的接口
autoProxy.setBeanNames("*ServiceImpl");
autoProxy.setInterceptorNames("newDataSourceAop", "tInterceptor");
return autoProxy;
}
注意,拦截器的顺序依赖于名字字符串传入的先后顺序,@Order什么的是完全没用的,因为保存这些拦截器的是一个字符串数组。自定义的事务AOP Advice:
public class TInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public TInterceptor() {
setTransactionAttributes(getAttrs());
}
private Properties getAttrs(){
Properties attributes = new Properties();
// 新增
attributes.setProperty("create*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
// 修改
attributes.setProperty("update*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
// 删除
attributes.setProperty("delete*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
//查询
attributes.setProperty("query*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT");
return attributes;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, () -> invocation.proceed());
}
}
自定义的读写分离Advice:
@EnableConfigurationProperties(ReadDBPathProperties.class)
public class NewDataSourceAop implements MethodBeforeAdvice {
private static final Logger log = LoggerFactory.getLogger(NewDataSourceAop.class); @Autowired
private ReadDBPathProperties readDBPathProperties; @Override
public void before(Method method, Object[] args, Object target) throws Throwable {
String clazzName = method.getDeclaringClass().getSimpleName();
String runner = clazzName + "." + method.getName();
this.chooseDataSource(runner);
} private void chooseDataSource(String runner){
runner += ",";
String read = readDBPathProperties.getReadPath()+",";
log.info("case : read path, vo : readPath = {}", read);
int index = read.indexOf(runner);
if (index == -1){
log.info("case : choose write DB, runner : {}, tid={}", runner, Thread.currentThread().getId());
HandleDataSource.putDataSource("write");
return;
}
log.info("case : choose read DB, runner : {}, tid={}", runner, Thread.currentThread().getId());
HandleDataSource.putDataSource("read");
}
}
最后再特别说一下,关于这个功能的单元测试,这个单元测试有一点意思,如果是直接运行测试方法,启动过程和执行过程在同一个线程是测试不出效果的,因为启动过程中加载Bean的时候会对下图中的resources初始化,写入默认的数据源:

就会导致后续执行的读写分离拦截器失效,只要保证执行线程和启动线程不在同一线程就好。
==========================================================
咱最近用的github:https://github.com/saaavsaaa
微信公众号:

Spring Boot 声明式事务结合相关拦截器的更多相关文章
- 使用注解实现Spring的声明式事务管理
使用注解实现Spring的声明式事务管理,更加简单! 步骤: 1) 必须引入Aop相关的jar文件 2) bean.xml中指定注解方式实现声明式事务管理以及应用的事务管理器类 3)在需要添加事务控制 ...
- Spring(四)Spring JdbcTemplate&声明式事务
JdbcTemplate基本使用 01-JdbcTemplate基本使用-概述(了解) JdbcTemplate是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装.spr ...
- 保护亿万数据安全,Spring有“声明式事务”绝招
摘要:点外卖时,你只需考虑如何拼单:选择出行时,你只用想好目的地:手机支付时,你只需要保证余额充足.但你不知道这些智能的背后,是数以亿计的强大数据的支持,这就是数据库的力量.那么庞大数据的背后一定会牵 ...
- spring aop 声明式事务管理
一.声明式事务管理的概括 声明式事务(declarative transaction management)是Spring提供的对程序事务管理的方式之一. Spring的声明式事务顾名思义就是采用声明 ...
- Spring之声明式事务
在讲声明式事务之前,先回顾一下基本的编程式事务 编程式事务: //1.获取Connection对象 Connection conn = JDBCUtils.getConnection(); try { ...
- 【Spring】——声明式事务配置详解
项目中用到了spring的事务: @Transactional(rollbackFor = Exception.class, transactionManager = "zebraTrans ...
- Spring AOP声明式事务异常回滚(转)
转:http://hi.baidu.com/iduany/item/20f8f8ed24e1dec5bbf37df7 Spring AOP声明式事务异常回滚 近日测试用例,发现这样一个现象:在业务代码 ...
- @Transactional、Spring的声明式事务
传送门 一.Spring的声明式事务 需要在xml文件中配置 <!--配置事务管理器类--> <bean id="transactionManager" clas ...
- Spring -12 -声明式事务及完整的XML配置文件信息 -声明式事务中的相关属性(tx:advice的标签)
1.编程式事务: 1.1由程序员编程事务控制代码. 1.2OpenSessionInView 就属于编程式事务: session.commit()和rollback() 2.声明式事务: 2.1事务控 ...
随机推荐
- MyEclipse常见错误
1.Could not create the view: An unexpected exception was thrown java.lang.NullPointerException a ...
- css锚点ios不兼容的方法
css锚点的正常方法: <a href="#1f"></a> <a name="1f"></a> ios出现的问 ...
- 对InvokeRequired的理解
if (listBox1.InvokeRequired) //当有新工作进程访问控件时InvokeRequired为True ...
- C++小技巧之CONTAINING_RECORD
CONTAINING_RECORD Containing record是一个在C++编程中用处很大的一种技巧,它的功能为已知结构体或类的某一成员.对象中该成员的地址以及这一结构体名或类名,从而得到该对 ...
- 每天一个linux命令(63):Linux中zip压缩和unzip解压缩命令详解
文章转自:http://www.jb51.net/LINUXjishu/105916.html 1.把/home目录下面的mydata目录压缩为mydata.zipzip -r mydata.zip ...
- 【转】JDBC学习笔记(9)——DBUtils的使用
转自:http://www.cnblogs.com/ysw-go/ 使用DBUtils提供的功能需要使用commons-dbutils-1.6.jar这个JAR包,在Apache官网可以下载到 使用D ...
- ArrayList 遍历
1.迭代器遍历 package sourceCode.ArrayList; import java.util.ArrayList; import java.util.Iterator; import ...
- 京东商城首页jquery轮播特效
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...
- Vim安装YouCompletMe插件。
1.Centos7.0自带含有支持python2.x的vim.(:version 后看python+则支持,python-则不支持)若不支持,卸载vim后源码编译安装. yum install pyt ...
- java虚拟机总结
jvm内存模型 u 程序计数器 u Java栈(虚拟机栈) u 本地方法栈 u Java堆 u 方法区及其运行时常量池 垃圾回收机制 u 新生代和老年代 u 参数设置 u 垃圾回收(M ...