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配置文件的略微差异. ...
随机推荐
- 获取网站资源 getResourceAsStream
获取网站资源(重点) public void doGet(HttpServletRequest request, HttpServletResponse response)throws Servlet ...
- HDUOJ----Good Luck in CET-4 Everybody!
Good Luck in CET-4 Everybody! Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (J ...
- c语言格式大整理
1.C语言中,非零值为真,真用1表示:零值为假,假用0表示. 2.转义字符参考: \a 蜂鸣,响铃 \b 回退:向后退一格 \f 换页 \n 换行 \r 回车,光标到本行行首 \t 水平制表 \v 垂 ...
- Python 的 pass 语句
Python pass是空语句,是为了保持程序结构的完整性. pass 不做任何事情,一般用做占位语句. 例子1: if __name__ == '__main__': pass 例子2: # 输出 ...
- mac下安装mysql 1820 重置默认密码
mac安装mysql时会给出一个临时密码 记录下来 2018-03-17T02:14:10.809431Z 1 [Note] A temporary password is generated for ...
- 权限管理系统(一):权限系统与RBAC模型概述
RBAC模型概述 RBAC即角色访问控制(Role Based Access Control) RBAC认为权限授权实际上是Who.What.How的问题.在RBAC模型中,who.what.how构 ...
- 更新yum源却忘了生成缓存 造成每次启动机器报:the package list needs to be rebuilt
更新yum源的后一定要执行下面的两条命令: yum clean all yum makecache 注意:如果有第三方源的时候是,开机发果不联网的时候,也会报这个错!!!!!
- MySQL数据库如何去掉数据库中重复记录
对于常规的MySQL数据表中可能存在重复的数据,有些情况是允许重复数据的存在,有些情况是不允许的,这个时候我们就需要查找并删除这些重复数据,以下是具体的处理方法! 方法一:防止表中出现重复数据 当表中 ...
- oracle 存储过程实现数据CURD操作
1.创建数据库表: -- Create table create table TEST_TABLE ( userid NUMBER not null, username NVARCHAR2(50), ...
- angular学习笔记(二)-创建angular模块
如果在页面的html标签(或任意标签)中添加ng-app,表示对整个页面应用angular来管理. 他是一个模块. 模块有助于把东西从全局命名空间中隔离. 今天学习如何自定义创建模块: <!DO ...