在Spring中启动时执行方法

Jav*_*avi 168 java spring

当应用程序第一次启动时,是否有任何Spring 3功能可以执行某些方法?我知道我可以设置一个带@Scheduled注释的方法,它只是在启动后执行,但它会定期执行.

ska*_*man 182

如果通过"应用程序启动"你的意思是"应用程序上下文启动",那么是的,有很多方法可以做到这一点,最简单的(对于单例bean,无论如何)是用你的方法注释@PostConstruct.看一下链接以查看其他选项,但总的来说它们是:

  • 用注释方法注释 @PostConstruct
  • afterPropertiesSet()InitializingBean回调接口定义
  • 自定义配置的init()方法

从技术上讲,这些是bean生命周期的钩子,而不是上下文生命周期,但在99%的情况下,这两者是等价的.

如果你需要专门挂钩上下文启动/关闭,那么你可以实现Lifecycle接口,但这可能是不必要的.

  • 经过相当多的研究,我还没有看到Lifecycle或SmartLifecycle的实现.我知道这已经有一年了,但是如果你有任何你可以发布的东西,我会非常感谢skaffman. (7认同)
  • 在创建整个应用程序上下文之前调用上述方法(例如,/之前/事务划分已经设置). (4认同)
  • 在重要的情况下,_bean_和_context_生命周期非常不同.正如@HansWesterbeek所指​​出的,可以在它所依赖的上下文完全就绪之前设置bean.在我的情况豆依赖于JMS - 它完全建立,所以它的`@ PostConstruct`方法被调用,但JMS基础结构也间接地依赖尚未完全连接好(并且是春天的一切只是默默地失败).切换到`@EventListener(ApplicationReadyEvent.class)`一切正常(`ApplicationReadyEvent`是针对vanilla Spring的Spring Boot,请参阅Stefan的回答). (2认同)

Ste*_*erl 102

这很容易用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 
  }
}
Run Code Online (Sandbox Code Playgroud)

应用程序侦听器在Spring中同步运行.如果您想确保只执行一次代码,只需在组件中保留一些状态即可.

UPDATE

从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 
  }
}
Run Code Online (Sandbox Code Playgroud)

  • NB对于那些想要使用`ContextStartedEvent`的人来说,在事件触发之前添加监听器会更加困难. (9认同)
  • 如何将@Autowired JPA repositopry称为事件?存储库为null. (2认同)

vph*_*nyc 36

在Spring 4.2+中,你现在可以简单地做到:

@Component
class StartupHousekeeper {

    @EventListener(ContextRefreshedEvent.class)
    void contextRefreshedEvent() {
        //do whatever
    }
}
Run Code Online (Sandbox Code Playgroud)


Zom*_*ies 12

如果你使用弹簧靴,这是最好的答案.

我觉得@PostConstruct和其他各种生命周期的插入是有关的方式.这些可能直接导致运行时问题或由于意外的bean /上下文生命周期事件而导致不明显的缺陷.为什么不直接使用普通Java调用bean?你仍然用'spring way'调用bean(例如:通过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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这通常是一个好主意,但是当从集成测试启动spring应用程序上下文时,main永远不会运行! (5认同)

enc*_*est 9

对于在尝试引用@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");
    }

}
Run Code Online (Sandbox Code Playgroud)


Wim*_*uwe 7

我们所做的是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..." );
    }
}
Run Code Online (Sandbox Code Playgroud)

然后配置子类web.xml:

<listener>
    <listener-class>
        com.mycomp.myapp.web.context.ContextLoaderListener
    </listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)


小智 6

使用SpringBoot,我们可以在启动时通过@EventListener注释执行方法

@Component
public class LoadDataOnStartUp
{   
    @EventListener(ApplicationReadyEvent.class)
    public void loadData()
    {
        // do something
    }
}

Run Code Online (Sandbox Code Playgroud)