springboot @PostConstruct方法被调用两次

时间:2017-12-20 14:41:21

标签: spring-boot

我注意到我的bean在jar中的spring-boot应用程序中两次调用@PostConstruct的{​​{1}}和init()两次。这是两次初始化的示例bean。

@Scheduled

@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被调用了两次:

从日志开始,首先调用PostConstruct:

@Scheduled
第二个被称为:

[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)

和@Scheduled一次被调用两次:

[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)

当我删除[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类只有一个实例。

1 个答案:

答案 0 :(得分: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,因此可以将其注入任何其他组件。