如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢?

本教程将介绍如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢?的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢? 教程 第1张

问题描述

我最近注意到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代理

这些工作方式基本上是创建代理,在对原始(代理)对象的调用之前/之后执行相关的建议逻辑。容器注册此代理,而不是代理对象本身,因此所有依赖项都设置为此代理,并且从一个bean到另一个bean的所有的子类。这样,它可以拦截@Configuration类的每个(非finalprivate)方法的调用,甚至在同一个对象中也是如此(因为这些方法实际上都被代理重写,并且Java将所有方法都设为虚的)。代理这样做正是为了将它识别为(语义上)对Spring bean的引用的任何方法调用重定向到实际的bean实例,而不是调用超类方法。

好了关于如果Spring可以成功拦截@Configuration类中的类内函数调用,那么为什么它在常规bean中不支持它呢?的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。