Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 462|回复: 0

Spring事务处理时自我调用的解决方案 嵌套AOP

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-6-10 16:08:00 | 显示全部楼层 |阅读模式

    开涛的解决方案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>

     

     

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-2 09:44 , Processed in 0.060433 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表