为什么@Configuration类中的@Autowired字段为null?

时间:2016-12-12 23:35:08

标签: java spring

这是the Spring documentation第6.12.5节的一个例子:

@Configuration
public class ServiceConfig {

    @Autowired
    private AccountRepository accountRepository;

    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl(accountRepository);
    }

}

我的问题是:为什么必须在accountRepository使用new TransferServiceImpl()之前创建transferService()?另外,我不知道Spring怎么知道第二个依赖于第一个被设置(除非它通过@Autowired字节码)。是因为关于Spring执行命令的顺序保证在@Bean方法可能被调用之前处理new变量?什么是处理订单?什么样的情况会导致Spring处理这些乱序?

我问的原因是我遇到过这样的情况,即null正在使用@Autowired参数执行。 log4j.logger.org.springframework.beans变量设置得太晚,或者根本没有设置(我的猜测是后者,基于一些@Autowired调试输出,但我不确定)。这种情况当然要复杂得多 - 这是一个很大的应用程序,配置类中还有一些@Bean@DependsOn定义。使用{{1}}没有帮助。通过删除代码来缩小问题需要花费大量时间,直到我能得到一个最小的例子,但我想看看我是否可以通过了解有关Spring如何处理事情的更多细节来了解问题,然后再开始困难的代码减少路径。

2 个答案:

答案 0 :(得分:5)

  

为什么必须在accountRepository使用之前创建TransferServiceImpl()   新accountRepository

它没有。 null可能会被视为@Configuration

来自documentation you linked(其最新版本)

中的注释
  

确保以这种方式注入的依赖项是   最简单的一种。 BeanPostProcessor类很早就得到了处理   在初始化上下文和强制依赖   以这种方式注入可能会导致意外的早期初始化。   尽可能采用基于参数的注射方法   上面的例子。

     

另外,请特别小心BeanFactoryPostProcessor 和   通过@Bean定义的static。通常应该这样做   声明为@Bean @Autowired方法,不触发实例化   他们包含的配置类。否则,@Value和   Configuration将无法在配置类本身上运行   太早创建为bean实例。

总之,@Autowired类最终只是应用程序上下文中的另一个bean。因此,它将由所有已注册的BeanPostProcessor bean处理。

AnnotationConfigApplicationContextAutowiredAnnotationBeanPostProcessor处理。据推测,您正在使用AccountRepository自动注册一个。

在您的示例中,自

以来不完整
  

...但确定autowired bean定义的确切位置   声明仍然有些含糊不清

但是,我们可以假设一些其他配置为ServiceConfig bean提供了bean定义。一旦应用程序上下文实例化@Autowired bean,它就可以对其进行后处理并注入@Autowired个目标。

null bean实例中@Configuration目标可能是AutowiredAnnotationBeanPostProcessor的唯一原因是您在@Configuration处理/注入它之前尝试读取它。< / p>

考虑循环依赖。使用以下类别中的@ComponentScan

获取代码段中的@Component class AccountRepository { public AccountRepository(Foo foo) {} } @Component class Foo { public Foo(TransferService ts) {} } 课程
@Configuration

AutowiredAnnotationBeanPostProcessor bean初始化。 accountRepository开始处理AccountRepository字段。它查找Foo bean并尝试初始化它。它需要一个Foo bean来实例化它(用于构造函数注入)。它查找TransferService bean并尝试初始化它。它需要一个TransferService bean来实例化它(用于构造函数注入)。它查找@Bean bean并找到accountRepository工厂方法。它调用它。 null尚未初始化,因此仍为@Bean。您可以通过在org.springframework.beans.factory.BeanCurrentlyInCreationException方法中放置断点并浏览堆栈跟踪来验证这一点。

您是否使用了上面引用中建议的参数注入

  

尽可能采用基于参数的注入,如上例所示。

春天会崩溃并警告你

  

引起:   'accountRepository':   创建名为let formatter = DateFormatter() //2016-12-08 03:37:22 +0000 formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z" let now = Date() let dateString = formatter.string(from:now) NSLog("%@", dateString) 的bean时出错:请求的bean是   目前正在创作:是否存在无法解决的循环引用?

  

这是我最终做的解决方法

我目前无法解释这一点。

答案 1 :(得分:0)

我只是将accountRepository移到方法的参数上,并使用@Autowired进行注释以解决此问题。但我不知道为什么。我认为原因是关于Spring的初始订单。

@Configuration
public class ServiceConfig {

    @Bean
    public TransferService transferService(@Autowired AccountRepository accountRepository) {
        return new TransferServiceImpl(accountRepository);
    }

}