我正在阅读一些有关Spring AOP的文章,并且遇到了这个问题:
AOP代理:由AOP创建以实现方面的对象 合同。在Spring中,代理对象可以是JDK动态代理,也可以是 CGLIB代理。默认情况下,代理对象将是动态的JDK 代理,并且要代理的对象必须实现一个接口, 也将由代理对象实现。但是像 CGLIB也可以通过子类化来创建代理,因此 不需要界面。
您能否看一下下面的结构,并想像一下我们想建议bar()
方法?
public interface Foo {
void foo();
}
public class FooImpl implements Foo {
@Override
public void foo() {
System.out.println("");
}
public void bar() {
System.out.println("");
}
}
这是否意味着在这种情况下将使用CGLIB代理?
由于JDK动态代理无法实现任何接口来覆盖bar()
方法。
答案 0 :(得分:2)
Spring只会在您告知时使用CGLIB。通过将proxyTargetClass
的{{1}}元素设置为@EnableAspectJAutoProxy
,可以启用此功能(对于基于注释的配置)。
true
考虑这个最小的示例(假设您的@EnableAspectJAutoProxy(proxyTargetClass = true)
用FooImpl
注释)
@Component
默认情况下,@Aspect
@Component
class FooAspect {
@Before("execution(public void bar())")
public void method() {
System.out.println("before");
}
}
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class Example {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Example.class);
FooImpl f = ctx.getBean(FooImpl.class); // throw exception here
f.bar();
}
}
是proxyTargetClass
。在这种情况下,Spring将不会使用CGLIB。由于false
类中的@Before
建议,Spring将决定需要使用JDK代理来代理@Aspect
。不幸的是,由于这种代理行为,实际存储在上下文中的bean将具有动态JDK FooImpl
类型(也是Proxy
接口的子类型),因此尝试使用{{ 1}}将失败。
即使您尝试将其作为Foo
进行检索,由于代理对象不是FooImpl.class
,您也无法调用Foo
方法。
如果启用bar()
,则上面的代码将按预期工作,将创建CGLIB代理,并调用FooImpl
建议。
答案 1 :(得分:0)
请参阅Spring文档中的AOP Proxies:
Spring AOP默认将标准JDK动态代理用于AOP代理。这样可以代理任何接口(或一组接口)。
Spring AOP也可以使用CGLIB代理。这对于代理类而不是接口是必需的。默认情况下,如果业务对象未实现接口,则使用CGLIB。
答案 2 :(得分:-1)
Spring AOP默认将标准JDK动态代理用于AOP代理。这样可以代理任何接口(或一组接口)。
Spring AOP也可以使用CGLIB代理。这对于代理类而不是接口是必需的。如果业务对象未实现接口,则默认情况下使用CGLIB。因为对接口而不是类进行编程是一种好习惯;业务类通常将实现一个或多个业务接口。在那些需要建议在接口上未声明的方法,或者需要将代理对象作为具体类型传递给方法的情况下(在极少数情况下),可以强制使用CGLIB。 / p>
重要的是要掌握Spring AOP基于代理的事实。请参阅了解AOP代理以全面了解此实现细节的实际含义。
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-introduction