spring boot @PostConstruct方法被调用两次

问题描述 投票:3回答:1

我注意到我的豆子在jar中的spring-boot应用程序中两次调用@PostConstructinit()@Scheduled两次。这是两次初始化的示例bean。

@Component
@ConfigurationProperties(prefix = "task")
public class CancelTask {
    private static Logger log = LoggerFactory.getLogger(CancelTask.class);

    @PostConstruct
    public void init() {
        log.info("CancelTask init:{}", this);
        printStackTrace();
    }

    private void printStackTrace() {
        StackTraceElement[] stackElements = new Throwable().getStackTrace();
        StringBuilder sb = new StringBuilder();
        if (stackElements != null) {
            for (int i = 0; i < stackElements.length; i++) {
                sb.append("" + stackElements[i] + "\n");
            }
        }
        log.info(sb.toString());
    }

    @Scheduled(cron = "0 */1 * * * ?")
    public void closeTask() {
        log.info("close task start....{}", this);
        printStackTrace();
    }
}

@PostConstruct@Scheduled被召唤两次:

从日志开始,PostConstruct首次被调用:

[INFO] [2017-12-20 19:54:29,872] [c.n.m.workbench.daemon.task.CancelTask]: CancelTask init:com.netease.mail.workbench.daemon.task.CancelTask@34451ed8
[INFO] [2017-12-20 19:54:29,873] [c.n.m.workbench.daemon.task.CancelTask]: com.netease.mail.workbench.daemon.task.CancelTask.printStackTrace(CancelTask.java:85)
com.netease.mail.workbench.daemon.task.CancelTask.init(CancelTask.java:81)
  sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366)
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311)
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
com.netease.mail.workbench.Application.main(Application.java:61)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)

第二个被称为:

[INFO] [2017-12-20 19:54:36,148] [c.n.m.workbench.daemon.task.CancelTask]: CancelTask init:com.netease.mail.workbench.daemon.task.CancelTask@34451ed8
[INFO] [2017-12-20 19:54:36,150] [c.n.m.workbench.daemon.task.CancelTask]: com.netease.mail.workbench.daemon.task.CancelTask.printStackTrace(CancelTask.java:85)
com.netease.mail.workbench.daemon.task.CancelTask.init(CancelTask.java:81)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366)
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311)
org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:409)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1620)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:400)
org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(ConfigurationPropertiesRebinder.java:107)
org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.rebind(ConfigurationPropertiesRebinder.java:90)
org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.onApplicationEvent(ConfigurationPropertiesRebinder.java:138)
org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder.onApplicationEvent(ConfigurationPropertiesRebinder.java:51)
org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration.afterSingletonsInstantiated(ConfigurationPropertiesRebinderAutoConfiguration.java:79)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:781)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
com.netease.mail.workbench.Application.main(Application.java:61)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)

和@Scheduled一次被叫两次:

[INFO] [2017-12-20 19:57:00,006] [c.n.m.workbench.daemon.task.CancelTask]: close task start....com.netease.mail.workbench.daemon.task.CancelTask@34451ed8
[INFO] [2017-12-20 19:57:00,006] [c.n.m.workbench.daemon.task.CancelTask]: close task start....com.netease.mail.workbench.daemon.task.CancelTask@34451ed8

当我删除@ConfigurationProperties时,@PostConstruct@Scheduled只被召唤一次。而且我非常确定CancelTaskclass只有一个实例。

spring-boot
1个回答
3
投票

这根本不与Spring Cloud有关(一些评论暗示这一点),因为我可以在没有它的情况下重现这种行为。

发生这种情况是因为你正在为CancelTask创建两个bean。一个由@Component创建(+由@ComponentScan扫描),另一个是由于@ConfigurationProperties(+启用@EnableConfigurationProperties(CancelTask.class))创建的。

如果我在本地运行相同的示例,我会得到不同的实例ID:

com.example.demo.CancelTask: CancelTask init:com.example.demo.SomethingProperties@273f65d9
com.example.demo.CancelTask: CancelTask init:com.example.demo.SomethingProperties@6066ff52

您不应该在单个Spring组件中混合应用程序功能和配置基础结构。你应该将这个组件分成两部分;经验法则:如果你不能命名你的配置属性类SomethingProperties,那么它可能比它应该做的更多。

由于配置属性是bean,因此可以将其注入任何其他组件。

© www.soinside.com 2019 - 2024. All rights reserved.