Yev*_*i N 4 java inheritance aop spring spring-aop
我知道Spring AOP的功能非常有限(它只能切入Spring bean的类的公共方法,并且只有在从类外部调用这些方法时).但是现在我发现了涉及接口的另一个令人困惑的限制.
通常,如果一个类被子类化,Spring AOP可以切入所有方法(甚至是被覆盖的方法):
public class A {
public void methodA() { } //OK, can cut in
}
public class B extends A {
@Override
public void methodA() { } //OK, can cut in
public void methodB() { } //OK, can cut in
}
Run Code Online (Sandbox Code Playgroud)
但是当我们在混合中添加一个接口时,对于Spring AOP来说,事情变得非常糟糕:
public interface I {
public void methodA();
}
public class A implements I {
@Override
public void methodA() { } //OK, can cut in
public void methodB() { } //Fail, cannot see or cut into this method
}
public class B extends A {
@Override
public void methodA() { } //Fail, cannot see or cut into this method
public void methodC() { } //Fail, cannot see or cut into this method
}
Run Code Online (Sandbox Code Playgroud)
首先,Spring AOP只能切入界面中的方法,其他任何东西 - 它都看不到.其次,它只能切入直接实现接口方法的方法 - A.methodA().它无法切入由B覆盖的相同方法.
我使用通用切入点表达式"execution(* method*(..))"来切入所有可能的方法,因此它不是表达式问题.
这种限制有什么办法吗?或者我应该忘记Spring AOP并使用不同的方法?
更新: 好的,我找到了问题的真正原因.我实际上是依靠Intellij IDEA的AOP插件来测试它.它应该将切入点链接到所有受影响的方法.但它使用的是"旧的"动态JDK代理策略,而不是新的CGLIB策略.所以它没有将它链接到所有方法,但是当我实际运行我的程序时,它会正确地切入所有方法.
我正在使用Spring Boot 2,它使用'新'CGLIB策略.但是在SB1上它可能仍然使用"旧的"动态JDK代理策略,因此它可能仍然无法在那里工作.
Spring将使用动态代理或cglib来实现AOP.
如果没有接口,则选择Cglib,然后它将有效地创建目标类的子类,并覆盖目标类中的所有方法.通过这种方式,除最终和静态方法外,所有方法都可以切入.
如果目标类是带接口的,那么Spring可能会使用其中一个接口使用动态代理,显然这只会影响接口中声明的方法.
在spring-boot 2.0之前,动态代理是默认策略.现在Cglib是spring-boot 2.0之后的默认策略.
在我看来,Spring可能会采用动态代理方法.您可以在application.yaml中添加spring.aop.proxy-target-class:true以强制使用Cglib.
如果您仍有问题,最好发布更完整的代码段,显示如何调用mothods.
| 归档时间: |
|
| 查看次数: |
879 次 |
| 最近记录: |