首页 新闻 会员 周边 捐助

springboot 中 @EnableAspectJAutoProxy 不起作用

0
悬赏园豆:5 [已解决问题] 解决于 2022-10-28 17:06

不废话,上代码(简化到了极致)

1、Service接口

package com.example.springboot1.service;

public interface ICalculator {
    int calculate(int a, int b);
}

2、Service 实现 

package com.example.springboot1.service;

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;

@Service
public class CalculatorImpl implements ICalculator{
    @Override
    public int calculate(int a, int b) {
        try{
            System.out.println(AopContext.currentProxy().getClass().getName());
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return a + b;
    }
}

3、Controller

package com.example.springboot1.ctrl;

import com.example.springboot1.service.ICalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController("/test/")
public class Root {

    @Autowired
    private ICalculator calculator;

    @RequestMapping("/calculate")
    public String calculate() {
        calculator.calculate(1, 2);
        return calculator.getClass().getName();
    }
}

4、启动类

package com.example.springboot1;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@SpringBootApplication
public class SpringBoot1Application {

    public static void main(String[] args) {
        SpringApplication.run(SpringBoot1Application.class, args);
    }
}

 

访问 http://localhost:8080/calculate 后,控制台出现异常:

java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.
    at org.springframework.aop.framework.AopContext.currentProxy(AopContext.java:69)
    at com.example.springboot1.service.CalculatorImpl.calculate(CalculatorImpl.java:11)

浏览器得到的内容是:

com.example.springboot1.service.CalculatorImpl

不但在 Service实现类中 AopContext.currentProxy() 不能调用,而且 注入到 controller 中的 service 对象,它也是直接的实现类,它的类型不应该是一个代理类型的吗?

背锅狼的主页 背锅狼 | 初学一级 | 园豆:51
提问于:2022-10-26 20:22
< >
分享
最佳答案
0

AopContext源码可以看看,只有生成代理对象的时候才会执行AopContext的setCurrentProxy方法否则AopContext.currentProxy()会报错。
SpringBoot创建Bean对象的过程大概是:CalculatorImpl类-->推断构造方法-->普通对象-->依赖注入-->Bean对象
只有在有aop的情况下才会生成代理对象,所以你在com.example.springboot1.service.CalculatorImpl.calculate方法上加上相关切面就不会报错了。
注意:
1:请不要在异步线程里使用AopContext.currentProxy()
2:AopContext.currentProxy()不能使用在非代理对象所在方法体内

收获园豆:5
花开重日 | 菜鸟二级 |园豆:209 | 2022-10-27 10:28

现在问题就在这里:为什么没有生成代理对象,而是直接用实现类创建的对象

在Controller 里返回注入的 Calculator 对象的类型,它就是直接实现的 CalculatorImpl 类型,而没有创建它的一个代理类!

背锅狼 | 园豆:51 (初学一级) | 2022-10-27 10:40

@血狼一族: SpringBoot创建Bean对象如果没有aop的就不会生成代理对象,ioc部分不会生成代理对象,其实就是相当于new了一个对象但是会自动给属性赋值,并不会一上来就生成一个代理对象,只有需要aop的情况才会生成代理对象。

花开重日 | 园豆:209 (菜鸟二级) | 2022-10-27 10:53

@花开重日: 怎么才算是“需要AOP”啊?

背锅狼 | 园豆:51 (初学一级) | 2022-10-27 14:04

@血狼一族: 使用@Aspect配置相关的切面呀比如:

@Component
@Aspect
public class LogUtil {
@Before("execution(* calculate*(..))")
public void printLog(){
System.out.println("执行打印日志的功能");
}
}

花开重日 | 园豆:209 (菜鸟二级) | 2022-10-27 14:14

@花开重日: 

这样还要自己来管理事务启动停止,还要把所有可能调用方法加到这里来

太麻烦了

以前我做过的一个项目里,根本不需要这些配置的

背锅狼 | 园豆:51 (初学一级) | 2022-10-27 17:35
其他回答(1)
0

已经解决了

只要在 Service 实现类上加上 @Transactional 注解,或者在一个 public 方法上加 @Transactional 注解就可以了

 

估计是Spring认为,如果 Service 实现不需要启动事务的话,就没必要代理它的数据库事务的开启和关闭。既然都不用管了,就干脆不创建代理了。

背锅狼 | 园豆:51 (初学一级) | 2022-10-28 16:48
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册