Spring事务处理时自我调用的解决方案 嵌套AOP
开涛的解决方案1 http://jinnianshilongnian.iteye.com/blog/1487235
AopContext.currentProxy() 原理
http://books.google.com.hk/books?id=jRVp2INtY1AC&pg=PA104&lpg=PA104&dq=Spring+AopContext&source=bl&ots=KXzss6euqJ&sig=B1LdkDTEACMgdmSSQp9SkMBPiwQ&hl=zh-CN&sa=X&ei=kx1vUoXIE4emkQWS_4CoBQ&ved=0CCkQ6AEwADgU#v=onepage&q&f=false
解决方案2
通过BeanPostProcessor 在目标对象中注入代理对象
public class SomeServiceImpl implements SomeService
{ public void someMethod()
{
someInnerMethod();
//foo...
} public void someInnerMethod()
{
//bar...
}
}
两个方法经过AOP代理,执行时都实现系统日志记录。单独使用someInnerMethod时,没有任何问题。但someMethod就有问题了。someMethod里调用的someInnerMethod方法是原始的,未经过AOP增强的。我们期望调用一次someMethod会记录下两条系统日志,分别是someInnerMethod和someMethod的,但实际上只能记录下someMethod的日志,也就是只有一条。在配置事务时也可能会出现问题,比如someMethod方法是REQUIRED,someInnerMethod方法是REQUIRES_NEW,someInnerMethod的配置将不起作用,与someMethod方法会使用同一个事务,不会按照所配置的打开新事务。
由于java这个静态类型语言限制,最后想到个曲线救国的办法,出现这种特殊情况时,不要直接调用自身方法,而通过AOP代理后的对象。在实现里保留一个AOP代理对象的引用,调用时通过这个代理即可。比如:
//从beanFactory取得AOP代理后的对象
SomeService someServiceProxy = (SomeService)beanFactory.getBean("someService"); //把AOP代理后的对象设置进去
someServiceProxy.setSelf(someServiceProxy); //在someMethod里面调用self的someInnerMethod,这样就正确了
someServiceProxy.someMethod();
但这个代理对象还要我们手动set进来,幸好SpringBeanFactory有BeanPostProcessor扩展,在bean初始化前后会统一传递给BeanPostProcess处理,繁琐的事情就可以交给程序了,代码如下,首先定义一个BeanSelfAware接口,实现了此接口的程序表明需要注入代理后的对象到自身。
public class SomeServiceImpl implements SomeService,BeanSelfAware
{
private SomeService self;//AOP增强后的代理对象
//实现BeanSelfAware接口
public void setSelf(Object proxyBean)
{
this.self = (SomeService)proxyBean
}
public void someMethod()
{
someInnerMethod();//注意这句,通过self这个对象,而不是直接调用的
//foo...
}
public void someInnerMethod()
{
//bar...
}
}
再定义一个BeanPostProcessor,beanFactory中的每个Bean初始化完毕后,调用所有BeanSelfAware的setSelf方法,把自身的代理对象注入自身……
public class InjectBeanSelfProcessor implements BeanPostProcessor
{ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
if(bean instanceof BeanSelfAware)
{
System.out.println("inject proxy:" + bean.getClass());
BeanSelfAware myBean = (BeanSelfAware)bean;
myBean.setSelf(bean);
return myBean;
}
return bean;
} public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
{
return bean;
}
}
最后,在BeanFactory配置中组合起来,只需要把BeanPostProcesser加进去就可以了,比平常多一行配置而已。
<!-- 注入代理后的bean到bean自身的BeanPostProcessor... -->
<bean class=" org.mypackage.InjectBeanSelfProcessor"></bean> <bean id="someServiceTarget" class="org.mypackage.SomeServiceImpl" /> <bean id="someService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="someServiceTarget" />
</property>
<property name="interceptorNames">
<list>
<value>someAdvisor</value>
</list>
</property>
</bean> <!-- 调用spring的DebugInterceptor记录日志,以确定方法是否被AOP增强 -->
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor" /> <bean id="someAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="debugInterceptor" />
</property>
<property name="patterns">
<list>
<value>.*someMethod</value>
<value>.*someInnerMethod</value>
</list>
</property>
</bean>
Spring事务处理时自我调用的解决方案 嵌套AOP的更多相关文章
- Spring事务处理时自我调用
1.预备知识 aop概念请参考[http://www.iteye.com/topic/1122401]和[http://jinnianshilongnian.iteye.com/blog/141859 ...
- 【spring源码学习】spring的aop目标对象中进行自我调用,且需要实施相应的事务定义的解决方案
转载:http://www.iteye.com/topic/1122740 1.预备知识 aop概念请参考[http://www.iteye.com/topic/1122401]和[http://ji ...
- SpringMVC系列(十五)Spring MVC与Spring整合时实例被创建两次的解决方案以及Spring 的 IOC 容器和 SpringMVC 的 IOC 容器的关系
一.Spring MVC与Spring整合时实例被创建两次的解决方案 1.问题产生的原因 Spring MVC的配置文件和Spring的配置文件里面都使用了扫描注解<context:compon ...
- Spring事务处理
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位. 数据库向用户提供保存当前程序状态的方法,叫事务提交(commit): ...
- java 之DelayQueue,TaskDelayed,handlerFactory,dataChange消息配置.收发等.java spring事务处理TransactionTemplate
java 之DelayQueue,TaskDelayed,handlerFactory,dataChange消息配置.收发等.java spring事务处理TransactionTemplate等. ...
- 在 Visual Studio 中调试时映射调用堆栈上的方法
本文转自:https://msdn.microsoft.com/zh-cn/library/dn194476.aspx 1.创建代码图,以便在调试时对调用堆栈进行可视化跟踪. 你可以在图中进行标注以跟 ...
- JavaScript是如何工作的:引擎,运行时和调用堆栈的概述!
摘要: 理解JS执行原理. 原文:JavaScript是如何工作的:引擎,运行时和调用堆栈的概述! 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 本文是旨在深入研究JavaScrip ...
- 编写SqlHelper使用,在将ExecuteReader方法封装进而读取数据库中的数据时会产生Additional information: 阅读器关闭时尝试调用 Read 无效问题,解决方法与解释
在自学杨中科老师的视频教学时,拓展编写SqlHelper使用,在将ExecuteReader方法封装进而读取数据库中的数据时 会产生Additional information: 阅读器关闭时尝试调用 ...
- struts2与spring集成时action的class属性值意义
struts2单独使用时action由struts2自己负责创建:与spring集成时,action实例由spring负责创建(依赖注入).这导致在两种情况下struts.xml配置文件的略微差异. ...
随机推荐
- CoInitialize和CoInitializeEx
1.CoInitialize和CoInitializeEx的功能 CoInitialize是在当前线程初始化Com组件的函数,并且初始化为STA模式(单线程模式),一般新的程序建议使用CoInitia ...
- 【LeetCode】120. Triangle (3 solutions)
Triangle Given a triangle, find the minimum path sum from top to bottom. Each step you may move to a ...
- 解决修改计算机名后tfs连接不上的错误
1,用vs 自带的工具命令 tf workspaces 查看集合 2,执行命令: >tf workspaces /collection:https://aaaa.visualstudio.com ...
- 解决 无法将文件" "复制到“bin\*.*”。对路径“bin\*.*”的访问被拒绝。
关于这个问题今天碰到了, 我的解决办法很简单: 删除bin目录下的所有文件,然后重新生成,就不报错了.
- RabbitMQ概念及环境搭建(四)RabbitMQ High Availability
#################################################### RabbitMQ High Availability #################### ...
- Bridge - 桥接模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- 使用用户自定义类型作为map的key
有时候我们想把用户自定义类型作为std::map的键值.方法一)最简单的方法就是实现该自定义类型的<操作符,代码如下:class Foo{public: Foo(int num_) ...
- Android 开发之 bindService() 通信
Service 启动方式有两种 startService(intent) bindService(intent,conn,Context.BIND_AUTO_CREATE) startService( ...
- CentOS 7 设置中文环境
在vultr上的虚拟机虽然安装了中文支持,但是默认显示英语. 只要修改 /etc/locale.conf 即可. LANG="zh_CN.UTF-8" LANGUAGE=" ...
- [k8s]kubespray(ansible)自动化安装k8s集群
kubespray(ansible)自动化安装k8s集群 https://github.com/kubernetes-incubator/kubespray https://kubernetes.io ...