11 ответов:
если под " запуском приложения "вы подразумеваете" запуск контекста приложения", то да, есть много способов сделать это, самый простой (для синглетных бобов, во всяком случае), чтобы аннотировать ваш метод с
@PostConstruct. Взгляните на ссылку, чтобы увидеть другие варианты, но в целом они таковы:
- методы с аннотацией
@PostConstructafterPropertiesSet()Как определеноInitializingBeanинтерфейс обратного вызова- пользовательский настроенный init() метод
технически, это крючки в bean жизненный цикл, а не жизненный цикл контекста, но в 99% случаев они эквивалентны.
Если вам нужно подключить конкретно в контексте запуска/выключения, то вы можете реализовать
Lifecycleинтерфейс вместо этого, но это, вероятно, не нужно.
это легко сделать с тегом
ApplicationListener. Я получил эту работу, слушая весны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 } }прослушиватели приложений работают синхронно весной. Если вы хотите убедиться, что код выполняется только один раз, просто сохраните некоторое состояние в своем компоненте.
обновление
начиная с весны 4.2+ вы также можете использовать
@EventListenerаннотация для наблюдения заContextRefreshedEvent(спасибо @bphilipnyc для указания этого out):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 } }
для пользователей Java 1.8, которые получают предупреждение при попытке ссылаться на аннотацию @PostConstruct, я закончил вместо этого piggybacking от аннотации @Scheduled, которую вы можете сделать, если у вас уже есть задание @Scheduled с fixedRate или fixedDelay.
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"); } }
Если вы используете spring-boot, это лучший ответ.
Я чувствую, что
@PostConstructи другие различные жизненные циклы междометия являются обходными путями. Это может привести непосредственно к проблемам во время выполнения или вызвать менее очевидные дефекты из-за неожиданных событий жизненного цикла bean/context. Почему нельзя просто напрямую ссылаться на объект, используя простой Java? Вы все еще вызываете Боб "весенний путь" (например: через прокси 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:<listener> <listener-class> com.mycomp.myapp.web.context.ContextLoaderListener </listener-class> </listener>
внимание, это только рекомендуется, если ваш
runOnceOnStartupметод зависит от a полной инициализации контекста Spring. Например: вы хотите вызвать dao с демаркацией сделкивы также можете использовать запланированный метод с fixedDelay set very high
@Scheduled(fixedDelay = Long.MAX_VALUE) public void runOnceOnStartup() { dosomething(); }это имеет то преимущество, что все приложение подключено (транзакции, Dao,...)
видел в планирование задач для запуска один раз, используя задачу Spring пространство имен
опубликовано другое решение, которое реализует WebApplicationInitializer и вызывается задолго до того, как будет создан экземпляр spring bean, если у кого-то есть этот прецедент
инициализируйте локаль и часовой пояс по умолчанию с помощью Spring configuration
Если вы хотите настроить компонент до полного запуска приложения, вы можете использовать
@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"); } } }
можно использовать
@EventListenerна вашем компоненте, который будет вызван после запуска сервера и инициализации всех компонентов.@EventListener public void onApplicationEvent(ContextClosedEvent event) { }
Comments