İlkbaharda başlangıçta yöntemi yürüt


176

Uygulama ilk kez başlatıldığında bazı yöntemleri yürütmek için herhangi bir Bahar 3 özelliği var mı? @ScheduledEk açıklama ile bir yöntem ayarlama hile yapabileceğimi biliyorum ve başlangıçtan hemen sonra yürütüyor, ancak daha sonra periyodik olarak yürütülecek.


1
@Scheduled ile ilgili hile nedir? tam olarak istediğim bu!
chrismarx

Yanıtlar:


185

Eğer "uygulama başlangıcı" ile "uygulama bağlamı başlangıcı" demek istiyorsanız, evet, bunu yapmanın birçok yolu vardır , en kolay (singletons fasulye için, her neyse), yönteminize açıklama eklemektir @PostConstruct. Diğer seçenekleri görmek için bağlantıya bir göz atın, ancak özet olarak bunlar:

  • Ek açıklama eklenmiş yöntemler @PostConstruct
  • afterPropertiesSet()InitializingBeangeri arama arayüzü tarafından tanımlandığı gibi
  • Özel yapılandırılmış init () yöntemi

Teknik olarak, bunlar bağlam yaşam döngüsü yerine fasulye yaşam döngüsüne kancalardır , ancak vakaların% 99'unda ikisi eşdeğerdir.

Özellikle bağlam başlatma / kapatma işlemine bağlanmanız gerekiyorsa, bunun yerine arabirimi uygulayabilirsinizLifecycle , ancak bu muhtemelen gereksizdir.


7
Biraz araştırma yaptıktan sonra henüz Yaşam Döngüsü veya SmartLifecycle uygulaması görmedim. Biliyorum bu bir yaşında, ama skaffman eğer sen-ebilmek takdir göndermek bir şey varsa çok takdir ediyorum.

4
Yukarıdaki yöntemler, tüm uygulama bağlamı oluşturulmadan önce çağrılır (örn. / Önce / işlem sınırlaması ayarlanmadan).
Hans Westerbeek

Java 1.8 Access restriction: The type PostConstruct is not accessible due to restriction on required library /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/jre/lib/rt.jar
@PostConstruct

2
Fasulye ve bağlam yaşam döngüsünün çok farklı olduğu önemli durumlar vardır . @HansWesterbeek'in belirttiği gibi, bir fasulye, bağlı olduğu bağlam tamamen hazır olmadan önce kurulabilir. Benim durumumda bir fasulye JMS'ye bağlıydı - tamamen inşa edildi, bu yüzden @PostConstructyöntemi çağrıldı, ancak dolaylı olarak bağlı olduğu JMS alt yapısı henüz tam olarak bağlanmadı (ve Bahar olmak her şey sessizce başarısız oldu). Geçiş Açık @EventListener(ApplicationReadyEvent.class)çalıştı her şeyi ( ApplicationReadyEventStefan'ın cevaba bakınız vanilya Bahar için Bahar Boot özgüdür).
George Hawkins

@Skaffman: Ya fasulyem herhangi bir fasulye tarafından sevk edilmezse ve fasulyeyi hiçbir yerde kullanılmadan başlatmak istersem
Sagar Kharab

104

Bu kolayca bir ile yapılır ApplicationListener. Bunu Spring'in dinlemesini sağladım 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 
  }
}

Uygulama dinleyicileri ilkbaharda eşzamanlı olarak çalışır. Kodunuzun yalnızca bir kez yürütüldüğünden emin olmak istiyorsanız, bileşeninizde bir durum bulundurun.

GÜNCELLEME

Spring 4.2+ ile başlayarak @EventListenerek açıklamayı gözlemlemek için de kullanabilirsiniz ContextRefreshedEvent(bunu belirtmek için @bphilipnyc sayesinde ):

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

1
Bu da benim için çalıştı - bir kerelik fasulye olmayan başlatma için mükemmel.
Rory Hunter

9
ContextStartedEventBunun yerine kullanmak isteyenler için not , olay başlamadan önce dinleyiciyi eklemek daha zordur.
OrangeDog

2
@Autowired JPA veri havuzunu etkinliğe nasıl çağırırım? depo boş.
e-info128

Benim için çalışmıyor. Bahar mvc 3 kullanıyorum. Bu uygulama onholication onvent (___) uygulama başladığında çağrılmaz. Herhangi bir yardım. İşte benim kod @Component ortak sınıf AppStartListener ApplicationListener <ContextRefreshedEvent> {public void onApplicationEvent (son ContextRefreshedEvent olayı) {System.out.println ("\ n \ n \ nUygulama olayında ekle"); }}
Vishwas Tyagi

@VishwasTyagi Konteynırınızı nasıl başlatıyorsunuz? AppStartListener'ınızın bileşen taramanızın bir parçası olduğundan emin misiniz?
Stefan Haberl

38

Bahar 4.2 ve sonrasında artık şunları yapabilirsiniz:

@Component
class StartupHousekeeper {

    @EventListener(ContextRefreshedEvent.class)
    public void contextRefreshedEvent() {
        //do whatever
    }
}

Bu dinleyicinin başlatma işleminden sonra yalnızca bir kez çağrılabileceği garanti ediliyor mu?
gstackoverflow

Hayır, yukarıdaki cevabımı gör. İlk kez yürütülüp yürütülmediğini kontrol etmek için dinleyicinizde biraz durum bulun
Stefan Haberl

13

Spring-boot kullanıyorsanız, bu en iyi cevaptır.

Ben @PostConstructve diğer çeşitli yaşam döngüsü enjeksiyonlarının yuvarlak yollar olduğunu hissediyorum . Bunlar doğrudan çalışma zamanı sorunlarına yol açabilir veya beklenmedik fasulye / bağlam yaşam döngüsü olayları nedeniyle belirgin hatalardan daha azına neden olabilir. Neden sadece doğrudan Java kullanarak fasulyenizi çağırmıyorsunuz? Fasulyeyi hala 'yay yolu' olarak çağırıyorsunuz (örneğin: yay AoP proxy'si aracılığıyla). Ve en iyisi, sade bir java, bundan daha basit olamaz. Bağlam dinleyicilerine veya tek zamanlayıcılara gerek yoktur.

@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();
    }
}

5
Bu genel olarak iyi bir fikirdir ancak bahar uygulama içeriğinizi bir entegrasyon testinden başlatırken ana asla çalıştırılmaz!
Jonas Geiregat

@JonasGeiregat: Ayrıca, hiç uygulama olmayan başka senaryolar da vardır, main()örneğin bir uygulama çerçevesi kullanırken (örn. JavaServer Faces).
sleske

9

@PostConstruct ek açıklamasına başvurmaya çalışırken bir uyarı alan Java 1.8 kullanıcıları için bunun yerine, fixedRate veya fixedDelay ile bir @Scheduled işiniz varsa yapabileceğiniz @Scheduled ek açıklamasını piggyback ettim.

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");
    }

}


7

Yaptığımız org.springframework.web.context.ContextLoaderListenerşey, içerik başladığında bir şeyler yazdırmaktı.

public class ContextLoaderListener extends org.springframework.web.context.ContextLoaderListener
{
    private static final Logger logger = LoggerFactory.getLogger( ContextLoaderListener.class );

    public ContextLoaderListener()
    {
        logger.info( "Starting application..." );
    }
}

Alt sınıfı yapılandırın ve ardından web.xml:

<listener>
    <listener-class>
        com.mycomp.myapp.web.context.ContextLoaderListener
    </listener-class>
</listener>

7

SpringBoot ile @EventListenerek açıklama ile başlangıçta bir yöntem yürütebiliriz

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

4

Dikkat, bu sadece runOnceOnStartupyönteminiz tamamen başlatılan bir bahar içeriğine bağlıysa önerilir . Örneğin: işlem sınırlaması olan bir dao çağırmak istiyorsunuz

FixedDelay ayarı çok yüksekken zamanlanmış bir yöntem de kullanabilirsiniz

@Scheduled(fixedDelay = Long.MAX_VALUE)
public void runOnceOnStartup() {
    dosomething();
}

Bu, tüm uygulamanın kablolanması avantajına sahiptir (İşlemler, Dao, ...)

görev ad alanını kullanarak görevleri bir kez çalışacak şekilde zamanlama bölümünde görülen


Kullanmaya göre bir avantaj görmüyorum @PostConstruct?
Wim Deblauwe

@WimDeblauwe, Trasaction sınırlaması ile bir Autowired dao çağırmak için sadece bu fasulye değil, tüm bağlamın başlatılması için dosomething () 'de ne yapmak istediğinize bağlıdır
Joram

5
@WimDeblauwe '@PostConstruct' yöntemi, fasulye başlatıldığında tetiklenir, tüm bağlam hazır olmayabilir (Fe İşlem yönetimi)
Joram

Bu post yapı veya herhangi bir arabirim veya olaydan daha zarif imo
aliopi


1
AppStartListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ApplicationReadyEvent){
            System.out.print("ciao");

        }
    }
}

2
SpringReadEvent ilkbaharda değil ilkbahar çizme 3
John Mercier

0

Bir fasulyeyi uygulamanız tam olarak çalışmaya başlamadan önce yapılandırmak istiyorsanız, aşağıdakileri kullanabilirsiniz @Autowired:

@Autowired
private void configureBean(MyBean: bean) {
    bean.setConfiguration(myConfiguration);
}

0

@EventListenerSunucu başlatıldıktan ve tüm çekirdekler başlatıldıktan sonra çağrılacak olan bileşeninizde kullanabilirsiniz .

@EventListener
public void onApplicationEvent(ContextClosedEvent event) {

}

0

StartupHousekeeper.javaPakette bulunan bir dosya için com.app.startup,

Bunu şu konumda yapın StartupHousekeeper.java:

@Component
public class StartupHousekeeper {

  @EventListener(ContextRefreshedEvent.class)
  public void keepHouse() {
    System.out.println("This prints at startup.");
  }
}

Ve bunu şu şekilde yapın myDispatcher-servlet.java:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <mvc:annotation-driven />
    <context:component-scan base-package="com.app.startup" />

</beans>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.