栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Spring注解驱动开发】困扰了我很久的AOP嵌套调用终于解决了

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Spring注解驱动开发】困扰了我很久的AOP嵌套调用终于解决了

Spring AOP在同一个类里自身方法相互调用时无法拦截。比如下面的代码:

public class SomeServiceImpl implements SomeService {

public void someMethod() {

someInnerMethod();

}

public void someInnerMethod(){

}

}

两个方法经过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{

//AOP增强后的代理对象

private SomeService self;

//实现BeanSelfAware接口

public void setSelf(Object proxyBean){

this.self = (SomeService)proxyBean

}

public void someMethod(){

//注意这句,通过self这个对象,而不是直接调用的

someInnerMethod();

}

public void someInnerMethod(){

}

}

再定义一个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加进去就可以了,比平常多一行配置而已。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/874477.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号