【问题标题】:Lazy load spring bean懒加载弹簧豆
【发布时间】:2018-04-26 10:56:44
【问题描述】:

如果一个bean被延迟加载,那么延迟加载的bean中定义的所有bean都会被延迟加载吗? (即使它们没有被定义@Lazy)

这里是测试项目: https://github.com/madhur/conditional-property-test/blob/master/src/main/java/com/example/demo/EventPublishService.java

我有这些豆子:

@Service
@ConditionalOnProperty(
        name = {"publish.feed.events"},
        havingValue = "true"
)
public class EventPublishService {
 
     @Autowired
     private KafkaPublisher kafkaPublisher;

}

//////////////////

@Service
public class EventService {

    @Autowired
    @Lazy
    private EventPublishService eventPublishService;

    @Value("${publish.feed.events:false}")
    private boolean isPublishEvents;
}

//////////////////////

@Component
public class KafkaPublisher {

    @Value("${kafka.producer.financial_feed.topic}")
    private String financeFeedTopic;
}

我的任何 application.properties 只有一个属性,

publish.feed.events=false

由于,我没有加载 EventPublishService bean(因为属性为 false),我希望依赖 bean KafkaPublisher 也不应该加载。但是,我在启动时收到错误,这意味着 KafkaPublisher bean 正在加载,即使 EventPublishService bean 没有被加载。

如何确保不加载 KafkaPublisher bean? 因此,对于不需要 EventPublishService bean 的任何人来说,属性不应该是强制性的吗?

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kafkaPublisher': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'kafka.producer.financial_feed.topic' in value "${kafka.producer.financial_feed.topic}"
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:379) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1344) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:578) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:501) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:760) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:395) [spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.1.RELEASE.jar:2.0.1.RELEASE]
        at com.example.demo.DemoApplication.main(DemoApplication.java:17) [main/:na] Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'kafka.producer.financial_feed.topic' in value "${kafka.producer.financial_feed.topic}"
        at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:172) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:124) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:237) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:211) ~[spring-core-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:839) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1086) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:373) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
        ... 16 common frames omitted

【问题讨论】:

  • 如果没有另外指定,它们将在加载延迟加载的 bean 的同时加载。
  • 我没有看到这种行为。无论如何都会加载其他传递 bean。
  • @MadhurAhuja 只是好奇,我的回答没有帮助吗?

标签: java spring


【解决方案1】:

作为stated in the doc

在创建容器时会创建单例范围并设置为预实例化(默认)的 Bean

因此,不管你把@Lazy放在@Autowired上,bean都会在启动时创建只要bean本身没有定义为lazy

@Component
public class KafkaPublisher {
    ...
}

如果你想延迟初始化这个bean,把@Lazy放在上面。如果你想让bean注入的过程变得懒惰,把@Lazy放在@Autowired上,就这么简单。

可以通过在@Configuration 类中声明它们并标记配置@Lazy 来延迟初始化一组相关bean。但是,请注意,一旦 @Configuration 类被初始化,所有声明的 bean 都将被初始化。

@Lazy
@Configuration
@ComponentScan(...) // will be lazily initialized with config
public class LazyConfiguration {

    @Bean
    public SomeBean beanName() { // will be lazily initialized with config
        return new SomeBean();
    } 

    @Bean
    public OtherBean beanName() { // will be lazily initialized with config
        return new OtherBean();
    }     
}

但是,当使用 @ComponentScan 时,请确保要延迟初始化的 bean(即 @Service@Component 等)尚未被其他上下文扫描。如果是,请将它们作为排除项添加到扫描该上下文中。


出于历史目的,下面的过时答案(在 OP 完全改变问题之前):

在 bean 中声明 bean 不是一个好习惯,但如果你将 @Configuration 标记为惰性,那么实际上其中的所有 bean 都将被惰性初始化,如 @Lazy 的 javadoc 中所述:

如果 @Configuration 类上存在 Lazy,则表示所有 @Configuration 中的 @Bean 方法应该被延迟初始化。

如果 "beans defined inside" 你实际上是指注入点,例如@Autowired,javadoc 也有答案:

懒惰的注解也可以放置在标记为的注入点上 Autowired 或 Inject:在这种情况下,它会导致创建一个 所有受影响依赖项的惰性解析代理,作为替代 使用 ObjectFactory 或 Provider。

然而,实际的自动装配 bean 将被急切地初始化(如果没有标记为 @Lazy 为好)。在这种情况下,注入本身是惰性的。

否则,请澄清你的意思。

【讨论】:

  • 提醒一下:所有的bean(如果不是@lazy)都会在上下文创建时初始化。我假设您知道并理解这一点。
  • 请看上面添加的细节。
  • @MadhurAhuja 更新了答案。告诉我是否足够清楚,或者我是否需要澄清一些事情
  • 谢谢。因此,除了对每个 bean 进行延迟之外,没有办法延迟加载整个相关 bean 集。
  • 确实如此。但是寻找其他人的意见总是有帮助的。
猜你喜欢
  • 2015-10-20
  • 2012-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多