在春季启动时执行方法
当应用程序第一次启动时,是否有Spring 3的特性来执行某些方法? 我知道我可以使用@Scheduled注释来设置一个方法,它会在启动之后执行,但是它会定期执行。
谢谢。
如果通过“应用程序启动”的意思是“应用程序上下文启动”,那么是的,有很多方法可以做到这一点 ,最简单的(对于单身bean,无论如何)是用@PostConstruct
注释你的方法。 看看链接,看看其他选项,但总的来说他们是:
- 用
@PostConstruct
注解的方法 - 由
InitializingBean
callback接口定义的afterPropertiesSet()
- 自定义configuration的init()方法
从技术上讲,这些都是钩入bean生命周期,而不是上下文生命周期,但在99%的情况下,这两者是等价的。
如果您需要专门挂接上下文启动/closures,那么您可以实现Lifecycle
界面 ,但这可能是不必要的。
这很容易用ApplicationListener
完成。 我得到这个工作听Spring的ContextRefreshedEvent
:
import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component public class StartupHousekeeper implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(final ContextRefreshedEvent event) { // do whatever you need here } }
应用程序侦听器在Spring中同步运行。 如果你想确保你的代码只执行一次,只要在你的组件中保持一些状态即可。
UPDATE
从Spring @EventListener
开始,您还可以使用@EventListener
注释来观察ContextRefreshedEvent (感谢@ bphilipnyc指出了这一点):
import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component; @Component public class StartupHousekeeper { @EventListener(ContextRefreshedEvent.class) public void contextRefreshedEvent() { // do whatever you need here } }
在4.2 +你现在可以简单地做:
@Component class StartupHousekeeper { @EventListener(ContextRefreshedEvent.class) void contextRefreshedEvent() { //do whatever } }
对于在试图引用@PostConstruct注解时得到警告的Java 1.8用户,我最终会捎带@Scheduled注释,如果您已经有一个带有fixedRate或fixedDelay的@Scheduled作业,您可以执行该注释。
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @EnableScheduling @Component public class ScheduledTasks { private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class); private static boolean needToRunStartupMethod = true; @Scheduled(fixedRate = 3600000) public void keepAlive() { //log "alive" every hour for sanity checks LOGGER.debug("alive"); if (needToRunStartupMethod) { runOnceOnlyOnStartup(); needToRunStartupMethod = false; } } public void runOnceOnlyOnStartup() { LOGGER.debug("running startup job"); } }
如果你正在使用弹簧启动,这是最好的答案。
我觉得@PostConstruct
和其他各种生命周期的感叹词都是四面八方的。 这些可能会直接导致运行时问题,或者由于意外的bean /上下文生命周期事件而导致不明显的缺陷。 为什么不直接用普通的Java调用你的bean呢? 你仍然调用bean的“spring的方式”(例如:通过spring的AoP代理)。 而最重要的是,这是普通的Java,不能比这更简单。 不需要上下文监听器或奇怪的调度器。
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { ConfigurableApplicationContext app = SpringApplication.run(DemoApplication.class, args); MyBean myBean = (MyBean)app.getBean("myBean"); myBean.invokeMyEntryPoint(); } }
我们所做的就是扩展org.springframework.web.context.ContextLoaderListener
来在上下文启动时打印一些东西。
public class ContextLoaderListener extends org.springframework.web.context.ContextLoaderListener { private static final Logger logger = LoggerFactory.getLogger( ContextLoaderListener.class ); public ContextLoaderListener() { logger.info( "Starting application..." ); } }
然后在web.xml
configuration子类:
<listener> <listener-class> com.mycomp.myapp.web.context.ContextLoaderListener </listener-class> </listener>
注意,只有在
runOnceOnStartup
方法依赖于完全初始化的spring上下文runOnceOnStartup
。 例如:你要用事务划分来调用一个dao
您也可以使用fixedDelay设置非常高的预定方法
@Scheduled(fixedDelay = Long.MAX_VALUE) public void runOnceOnStartup() { dosomething(); }
这有一个好处,整个应用程序连线(交易,道,…)
在使用Spring任务命名空间调度任务运行一次中看到
发布了另一个实现了WebApplicationInitializer的解决scheme,并且在任何spring bean实例化之前被调用,以防有人拥有该用例
使用Springconfiguration初始化默认的Locale和Timezone
如果要在应用程序运行完毕之前configuration一个bean,可以使用@Autowired
:
@Autowired private void configureBean(MyBean: bean) { bean.setConfiguration(myConfiguration); }
AppStartListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { if(event instanceof ApplicationReadyEvent){ System.out.print("ciao"); } } }