解决spring AOP中自身方法调用无法应用代理的问题
程序员文章站
2022-03-29 23:07:35
目录spring aop中自身方法调用无法应用代理(1)在myserviceimpl中声明一个myservice对象(2)使用aopcontext类spring aop中自身方法调用无法应用代理如下例...
spring aop中自身方法调用无法应用代理
如下例
public class myserviceimpl implements myservice { public void do(){ //the transaction annotation won't work if you directly invoke handle() method with 'this' this.handle(); } @transactional(propagation=propagation.required, rollbackfor=exception.class) public void handle() { //sth with transaction } }
如果直接调用this的handle()方法则事务无法生效,原因是spring的aop是通过代理实现的,像这样直接调用本对象的方法是不会应用代理的。
可以使用如下两种方式修改代码以应用事务
(1)在myserviceimpl中声明一个myservice对象
public class myserviceimpl implements myservice { @autowired private myservice myservice; public void do(){ //use myservice object myservice.handle(); } @transactional(propagation=propagation.required, rollbackfor=exception.class) public void handle() { //sth. with transaction } }
(2)使用aopcontext类
public class myserviceimpl implements myservice { public void do(){ //fetch current proxy objet from aopcontext ((myservice)aopcontext.currentproxy()).handle(); } @transactional(propagation=propagation.required, rollbackfor=exception.class) public void handle() { //sth with transaction } }
注意,原生的aspectj是不会有这种自身调用的问题的,因为它不是基于代理的aop框架。
spring aop 内部方法调用事务不生效
方法1:
基于 proxy 的 spring aop 带来的内部调用问题可以使用 aopcontext.currentproxy() 强转为当前的再调用就可以解决了
例如:
错误用法:
public account getaccountbyname2(string username) { return this.getaccountbyname(username); }
修改为:
public account getaccountbyname2(string username) { return ((accountservice)aopcontext.currentproxy()).getaccountbyname(username); }
另外注意:要设置aop实体暴露出来。在springboot的application.java里面加上
@enableaspectjautoproxy(proxytargetclass = true, exposeproxy = true)
方法2:
利用初始化方法在目标对象中注入代理对象
在目标对象类中注入spring上下文,通过context获取代理对象,并调用代理对象的方法。
注意:该方案对于scope为prototype的bean无法适用,因为每次获取bean时都返回一个新的对象。
方法2.1:
//延迟加载方式 private testservice testservice; @autowired @lazy public void settestservice(testservice testservice) { this.testservice = testservice; }
方法2.2:
import javax.annotation.postconstruct; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.applicationcontext; import org.springframework.stereotype.service; import com.blog.common.aop.service.testservice; @service public class testserviceimpl implements testservice { @autowired private applicationcontext context; private testservice proxyobject; @postconstruct // 初始化方法,在ioc注入完成后会执行该方法 private void setself() { // 从spring上下文获取代理对象(直接通过proxyobject=this是不对的,this是目标对象) // 此种方法不适合于prototype bean,因为每次getbean返回一个新的bean proxyobject = context.getbean(testservice.class); } public void methoda() throws exception { system.out.println("method a run"); system.out.println("method a 中调用method b,通过注入的代理对象,调用代理对象的方法,解决内部调用实现的问题。"); proxyobject.methodb(); //调用代理对象的方法,解决内部调用失效的问题 } public void methodb() { system.out.println("method b run"); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。