İ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.