Java 在 Spring 启动时执行方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2401489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute method on startup in Spring
提问by Javi
Is there any Spring 3 feature to execute some methods when the application starts for the first time? I know that I can do the trick of setting a method with @Scheduled
annotation and it executes just after the startup, but then it will execute periodically.
当应用程序第一次启动时,是否有任何 Spring 3 功能可以执行某些方法?我知道我可以用@Scheduled
注释设置方法,它会在启动后立即执行,但它会定期执行。
采纳答案by skaffman
If by "application startup" you mean "application context startup", then yes, there are many ways to do this, the easiest (for singletons beans, anyway) being to annotate your method with @PostConstruct
. Take a look at the link to see the other options, but in summary they are:
如果“应用程序启动”是指“应用程序上下文启动”,那么是的,有很多方法可以做到这一点,最简单的(无论如何对于单例 bean)是用@PostConstruct
. 查看链接以查看其他选项,但总而言之,它们是:
- Methods annotated with
@PostConstruct
afterPropertiesSet()
as defined by theInitializingBean
callback interface- A custom configured init() method
- 带有注释的方法
@PostConstruct
afterPropertiesSet()
由InitializingBean
回调接口定义- 自定义配置的 init() 方法
Technically, these are hooks into the beanlifecycle, rather than the context lifecycle, but in 99% of cases, the two are equivalent.
从技术上讲,这些是bean生命周期的钩子,而不是上下文生命周期,但在 99% 的情况下,两者是等效的。
If you need to hook specifically into the context startup/shutdown, then you can implement the Lifecycle
interfaceinstead, but that's probably unnecessary.
如果您需要专门挂钩上下文启动/关闭,那么您可以改为实现该Lifecycle
接口,但这可能是不必要的。
回答by Stefan Haberl
This is easily done with an ApplicationListener
. I got this to work listening to Spring's ContextRefreshedEvent
:
使用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
}
}
Application listeners run synchronously in Spring. If you want to make sure you're code is executed only once, just keep some state in your component.
应用程序侦听器在 Spring 中同步运行。如果你想确保你的代码只执行一次,只需在你的组件中保留一些状态。
UPDATE
更新
Starting with Spring 4.2+ you can also use the @EventListener
annotation to observe the ContextRefreshedEvent
(thanks to @bphilipnycfor pointing this out):
从 Spring 4.2+ 开始,您还可以使用@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
}
}
回答by Wim Deblauwe
What we have done was extending org.springframework.web.context.ContextLoaderListener
to print something when the context starts.
我们所做的是扩展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..." );
}
}
Configure the subclass then in web.xml
:
配置子类然后在web.xml
:
<listener>
<listener-class>
com.mycomp.myapp.web.context.ContextLoaderListener
</listener-class>
</listener>
回答by kisna
Posted another solution that implements WebApplicationInitializer and is called much before any spring bean is instantiated, in case someone has that use case
发布了另一个实现 WebApplicationInitializer 的解决方案,并在任何 spring bean 实例化之前被调用,以防有人有该用例
Initialize default Locale and Timezone with Spring configuration
回答by encrest
For Java 1.8 users that are getting a warning when trying to reference the @PostConstruct annotation, I ended up instead piggybacking off the @Scheduled annotation which you can do if you already have an @Scheduled job with fixedRate or fixedDelay.
对于在尝试引用 @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");
}
}
回答by Zombies
If you are using spring-boot, this is the best answer.
如果您使用的是 spring-boot,这是最好的答案。
I feel that @PostConstruct
and other various life cycle interjections are round-about ways. These can lead directly to runtime issues or cause less than obvious defects due to unexpected bean/context lifecycle events. Why not just directly invoke your bean using plain Java? You still invoke the bean the 'spring way' (eg: through the spring AoP proxy). And best of all, it's plain java, can't get any simpler than that. No need for context listeners or odd schedulers.
我觉得@PostConstruct
和其他各种生命周期感叹词都是迂回的方式。由于意外的 bean/上下文生命周期事件,这些可能直接导致运行时问题或导致不太明显的缺陷。为什么不直接使用纯 Java 调用您的 bean?您仍然以“弹簧方式”调用 bean(例如:通过弹簧 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();
}
}
回答by Cory Klein
If you want to configure a bean before your application is running fully, you can use @Autowired
:
如果要在应用程序完全运行之前配置 bean,可以使用@Autowired
:
@Autowired
private void configureBean(MyBean: bean) {
bean.setConfiguration(myConfiguration);
}
回答by Joram
Attention, this is only advised if your
runOnceOnStartup
method depends on a fully initialized spring context. For example: you wan to call a dao with transaction demarcation
注意,仅当您的
runOnceOnStartup
方法依赖于完全初始化的 spring 上下文时才建议这样做。例如:你想调用一个带有事务划分的 dao
You can also use a scheduled method with fixedDelay set very high
您还可以使用固定延迟设置非常高的预定方法
@Scheduled(fixedDelay = Long.MAX_VALUE)
public void runOnceOnStartup() {
dosomething();
}
This has the advantage that the whole application is wired up (Transactions, Dao, ...)
这样做的好处是整个应用程序都已连接起来(交易、Dao 等)
seen in Scheduling tasks to run once, using the Spring task namespace
回答by dnocode
AppStartListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ApplicationReadyEvent){
System.out.print("ciao");
}
}
}
回答by vphilipnyc
In Spring 4.2+ you can now simply do:
在 Spring 4.2+ 中,您现在可以简单地执行以下操作:
@Component
class StartupHousekeeper {
@EventListener(ContextRefreshedEvent.class)
public void contextRefreshedEvent() {
//do whatever
}
}