java – 懒惰加载spring bean

如果一个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.但是,我在启动时收到错误,这意味着即使没有加载EventPublishService bean,KafkaPublisher 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

最佳答案
stated in the doc,

Beans that are singleton-scoped and set to be pre-instantiated (the default) are created when the container is created

因此,如果将@Lazy放在@Autowired上并不重要,只要bean本身没有定义为懒惰,就会在启动时创建bean:

@Component
public class KafkaPublisher {
    ...
}

如果你希望这个bean被懒惰地初始化,就把@Lazy放在上面.如果你想让bean注入过程变得懒惰,就把@Lazy放在@Autowired上,就这么简单.

懒惰地初始化一组相关的bean可以通过在@Configuration类中声明它们并标记配置@Lazy来实现.但是,请注意,只要@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标记为lazy,那么它内部的所有bean都会被懒惰地初始化,如@ Lazy的javadoc中所述:

If Lazy is present on a @Configuration class, this indicates that all
@Bean methods within that @Configuration should be lazily initialized.

如果通过“内部定义的bean”实际上意味着注入点,例如@Autowired,javadoc也有答案:

Lazy annotation may also be placed on injection points marked with
Autowired or Inject: In that context, it leads to the creation of a
lazy-resolution proxy for all affected dependencies, as an alternative
to using ObjectFactory or Provider.

但是,实际的autowired bean将被急切地初始化(如果没有标记为@Lazy).在这种情况下,注射本身就是懒惰的.

否则,请澄清你的意思.

转载注明原文:java – 懒惰加载spring bean - 代码日志