欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解决spring AOP中自身方法调用无法应用代理的问题

程序员文章站 2022-06-26 09:19:41
目录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");
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。