【发布时间】:2020-05-06 10:25:57
【问题描述】:
我正在尝试对 Spring 代理的工作原理进行深入了解。为什么我应该在我的应用程序中使用“API Interface & Impl Bean”模式或只使用“Bean Class”模式。我读了很多 SO 答案,但它们都非常古老,我相信它们大多与 Java 7 with Spring 3.x 相关。我想知道 Java 11+ 和 Spring 5.x(Spring Boot 2.x)在 2020 年还有什么意义。有没有可以遵循的“最佳实践”?
另外,在@FunctionalInterface 可用的情况下,如果我的bean 正在实现Consumer、Function、Predicate 和类似的接口,那么@Autowire/@Inject 是否有意义而不是Consumer<A> Foo 其中Foo implements Consumer<A>。这只是一个例子,我可能也在使用我自己的功能接口(有或没有泛型)。
考虑到以上所有内容,我还想知道 Spring 创建的每个 bean 是否都被代理,或者如果实际上不需要,spring 是否在不代理它们的情况下创建 bean。例如。如果一个类只是简单地用@Component注解并直接注入,没有其他注解或代理要求,spring还会为这个bean创建一个代理吗?
一些我已经看过的问题:
- Why always have single implementation interfaces in service and dao layers?
- what reasons are there to use interfaces (Java EE or Spring and JPA)
- What is the difference between JDK dynamic proxy and CGLib?
2020 年 5 月 7 日更新:
在阅读了更多文章、cmets 和答案之后,我想谈谈我想到的确切问题/查询。让我们考虑以下示例。我有一个课程Foo 和AnotherFoo。
@Component
@RequiredArgsConstructor // From lombok
class Foo extends Consumer<Bar> {
// Some private final Fields
public void accept(Bar bar) {
// do something
}
// Some private methods, no other public method
}
选项 1:
@Component
@RequiredArgsConstructor // From lombok
class AnotherFoo {
private final Foo foo;
// Use foo only to call foo.accept(bar)
}
选项 2:
@Component
@RequiredArgsConstructor // From lombok
class AnotherFoo {
private final Consumer<Bar> foo;
// Use foo only to call foo.accept(bar)
}
现在在上述情况下,如果我们谈论 Spring 代理 Foo 的 bean,那么编写 AnotherFoo 的最佳方式可能是什么 - 选项 1 或 选项 2 或者可能与 AnotherFoo 的编写方式无关。我没有在代码中的任何地方使用@EnableAspectJAutoProxy,所以这里默认运行,很可能类似于Case 3 of A2 of this SO question。
额外问题:另外,如果在这里/任何地方使用 CGLib 进行代理,我知道它会操纵字节码来创建代理。在一些文章中,我可以读到这种方法构成了安全威胁。我想了解这是否真的是一个问题,如果是,这将如何影响应用程序?
【问题讨论】:
-
不,bean 并非总是代理;至少,完全可以创建一个
final类的 bean。 -
如果类不是final怎么办?
-
请浏览此答案的A2部分stackoverflow.com/a/59770104/4214241
-
此外,非最终类仅在必要时才被代理,因为您使用 Spring AOP 中实现的横切功能,该功能在 Spring 内部也用于一些横切关注点,例如事务和可能(我不是 Spring 用户,因此猜测)也是为了安全(授权),仅举几例。只要您自己的应用程序或 Spring 本身不“挂钩” bean 以使用拦截器、建议或其他附加功能来装饰它,就不会创建代理。这是按需进行的。
标签: java spring spring-boot spring-aop