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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:04:55  来源:igfitidea点击:

Execute method on startup in Spring

javaspring

提问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 @Scheduledannotation 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 the InitializingBeancallback 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 Lifecycleinterfaceinstead, 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 @EventListenerannotation 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.ContextLoaderListenerto 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

使用 Spring 配置初始化默认语言环境和时区

回答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 @PostConstructand 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 runOnceOnStartupmethod 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

调度任务运行一次中看到,使用 Spring 任务命名空间

回答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
    }
}