不废话,上代码(简化到了极致)
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 对象,它也是直接的实现类,它的类型不应该是一个代理类型的吗?
AopContext源码可以看看,只有生成代理对象的时候才会执行AopContext的setCurrentProxy方法否则AopContext.currentProxy()会报错。
SpringBoot创建Bean对象的过程大概是:CalculatorImpl类-->推断构造方法-->普通对象-->依赖注入-->Bean对象
只有在有aop的情况下才会生成代理对象,所以你在com.example.springboot1.service.CalculatorImpl.calculate方法上加上相关切面就不会报错了。
注意:
1:请不要在异步线程里使用AopContext.currentProxy()
2:AopContext.currentProxy()不能使用在非代理对象所在方法体内
现在问题就在这里:为什么没有生成代理对象,而是直接用实现类创建的对象
在Controller 里返回注入的 Calculator 对象的类型,它就是直接实现的 CalculatorImpl 类型,而没有创建它的一个代理类!
@血狼一族: SpringBoot创建Bean对象如果没有aop的就不会生成代理对象,ioc部分不会生成代理对象,其实就是相当于new了一个对象但是会自动给属性赋值,并不会一上来就生成一个代理对象,只有需要aop的情况才会生成代理对象。
@花开重日: 怎么才算是“需要AOP”啊?
@血狼一族: 使用@Aspect配置相关的切面呀比如:
@Component
@Aspect
public class LogUtil {
@Before("execution(* calculate*(..))")
public void printLog(){
System.out.println("执行打印日志的功能");
}
}
@花开重日:
这样还要自己来管理事务启动停止,还要把所有可能调用方法加到这里来
太麻烦了
以前我做过的一个项目里,根本不需要这些配置的
已经解决了
只要在 Service 实现类上加上 @Transactional 注解,或者在一个 public 方法上加 @Transactional 注解就可以了
估计是Spring认为,如果 Service 实现不需要启动事务的话,就没必要代理它的数据库事务的开启和关闭。既然都不用管了,就干脆不创建代理了。