我注意到我的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
类只有一个实例。
答案 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,因此可以将其注入任何其他组件。