If Spring can successfully intercept intra class function calls in a @Configuration class, why does it not support it in a regular bean?(如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢?)
问题描述
我最近注意到Spring在@Configuration类中成功拦截了类内函数调用,但在常规bean中没有成功拦截。
这样的电话
@Repository
public class CustomerDAO {
@Transactional(value=TxType.REQUIRED)
public void saveCustomer() {
// some DB stuff here...
saveCustomer2();
}
@Transactional(value=TxType.REQUIRES_NEW)
public void saveCustomer2() {
// more DB stuff here
}
}
无法启动新事务,因为当saveCustomer()的代码在CustomerDAO代理中执行时,saveCustomer2()的代码在未包装的CustomerDAO类中执行,正如我通过查看调试器中的‘this’可以看到的那样,因此Spring没有机会拦截对saveCustomer2的调用。
但是,在下面的示例中,当transactionManager()调用createDataSource()时,它被正确截获并调用代理的createDataSource(),而不是未包装类的createDataSource(),这可以通过查看调试器中的"this"来证明。
@Configuration
public class PersistenceJPAConfig {
@Bean
public DriverManagerDataSource createDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//dataSource.set ... DB stuff here
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager( ){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(createDataSource());
return transactionManager;
}
}
所以我的问题是,为什么Spring可以正确地拦截第二个示例中的类内函数调用,而不是第一个示例中的类内函数调用。它是否使用不同类型的动态代理?
编辑: 从这里和其他来源的答案中,我现在了解到以下几点: @Transaction是使用Spring AOP实现的,其中代理模式是通过包装/组合User类来实现的。AOP代理足够通用,因此许多方面可以链接在一起,并且可以是CGLib代理或Java动态代理。
在@Configuration类中,Spring还使用CGLib创建一个从User@Configuration类继承的增强类,并使用在调用用户的/超级函数(如检查这是否是第一次调用该函数)之前执行一些额外工作的函数覆盖用户的@Bean函数。这个类是代理吗?这取决于定义。您可能会说它是一个代理,它使用来自真实对象的继承,而不是使用组合包装它。 总而言之,从这里给出的答案我理解这是两种完全不同的机制。为什么做出这些设计选择是另一个悬而未决的问题。AOP
因为推荐答案代理和@Configuration
类的用途不同,实现方式也明显不同(即使两者都涉及使用代理)。
基本上,AOP使用组合,而@Configuration使用继承。
AOP代理
这些工作方式基本上是创建代理,在委托对原始(代理)对象的调用之前/之后执行相关的建议逻辑。容器注册此代理,而不是代理对象本身,因此所有依赖项都设置为此代理,并且从一个bean到另一个bean的所有调用都通过此代理。但是,被代理的对象本身没有指向代理的指针(它不知道它被代理了,只有代理有指向目标对象的指针)。因此对象内对其他方法任何调用都不会通过代理。
(我在此添加此内容只是为了与@Configuration形成对比,因为您似乎对此部分有正确的理解。)
@配置
现在,虽然您通常应用AOP代理的对象是应用程序的标准部分,但是@Configuration
类是不同的-首先,您可能永远不打算直接创建该类的任何实例。这个类实际上只是一种编写bean容器配置的方法,在Spring之外没有任何意义,您知道Spring将以一种特殊的方式使用它,并且它在纯Java代码之外有一些特殊的语义-例如,@Bean
注释的方法实际上定义了Spring bean。
正因为如此,Spring可以对该类执行更激进的操作,而不必担心它会破坏代码中的某些内容(请记住,您知道您只为Spring提供了此类,并且您永远不会直接创建或使用它的实例)。
它实际做的是创建一个代理,它是@Configuration
类
@Configuration
类的每个(非final
非private
)方法的调用,甚至在同一个对象中也是如此(因为这些方法实际上都被代理重写,并且Java将所有方法都设为虚的)。代理这样做正是为了将它识别为(语义上)对Spring bean的引用的任何方法调用重定向到实际的bean实例,而不是调用超类方法。
这篇关于如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢?
基础教程推荐
- 由于对所需库 rt.jar 的限制,对类的访问限制? 2022-01-01
- 如何强制对超级方法进行多态调用? 2022-01-01
- 如何在不安装整个 WTP 包的情况下将 Tomcat 8 添加到 Eclipse Kepler 2022-01-01
- 如何对 HashSet 进行排序? 2022-01-01
- 首次使用 Hadoop,MapReduce Job 不运行 Reduce Phase 2022-01-01
- 如何使用 Eclipse 检查调试符号状态? 2022-01-01
- Java 中保存最后 N 个元素的大小受限队列 2022-01-01
- 如何使用 Stream 在集合中拆分奇数和偶数以及两者的总和 2022-01-01
- 在螺旋中写一个字符串 2022-01-01
- Spring Boot Freemarker从2.2.0升级失败 2022-01-01