Sunucu uygulaması tabanlı bir web uygulamasında bir arka plan görevi nasıl çalıştırılır?


97

Java kullanıyorum ve uygulamamda bir sunucu uygulamasının sürekli çalışmasını sağlamak istiyorum, ancak bunu nasıl yapacağımı bilmiyorum. Sunucu uygulamamın, bir veritabanından günlük olarak kullanıcı sayılarının yanı sıra tüm veritabanındaki toplam kullanıcı sayısını veren bir yöntemi vardır. Bu yüzden sunucu uygulamasının bunun için sürekli çalışmasını istiyorum.


"Sürekli koşmak" derken ne demek istiyorsun?
skaffman

1
Sürekli koşmakla ne demek istiyorsun? Uygulama sunucunuz çalıştığı sürece çalışacaktır
fmucar

2
Neden sürekli çalışması gerektiğini anlamıyorum ... eğer birisi 'kullanıcı sayımı' istiyorsa servlet yönteminizi çağırıyor ve siz ona veriyorsunuz?
trojanfoe

@trojanfoe Aslında kullanıcı sayısını günlük olarak istiyorum, bu yüzden bunun için servlet'i her gün manuel olarak çalıştırmak zorunda kalacağım, bu yüzden bunu yapmak yerine servlet'i sürekli çalıştırmak istiyorum. bu yüzden servlet'i her gün çalıştırmam gerekmeyecek.
pritsag

1
@pritsag: Toplu işleri çalıştırmak için değil, kullanıcı isteklerine hizmet etmek için bir sunucu uygulaması vardır.
skaffman

Yanıtlar:


217

Sizin sorununuz, sunucu uygulamasının amacını yanlış anlamanızdır . HTTP isteklerine göre hareket etmek amaçlanmıştır, daha fazlası değil. Sadece günde bir kez çalışan bir arka plan görevi istiyorsunuz.

EJB mevcut mu? Kullanım@Schedule

Ortamınız EJB'yi (ör. WildFly, JBoss, TomEE, Payara, GlassFish, vb. Gibi gerçek bir Java EE sunucusu) destekliyorsa, @Schedulebunun yerine kullanın. İşte bazı örnekler:

@Singleton
public class BackgroundJobManager {

    @Schedule(hour="0", minute="0", second="0", persistent=false)
    public void someDailyJob() {
        // Do your job here which should run every start of day.
    }

    @Schedule(hour="*/1", minute="0", second="0", persistent=false)
    public void someHourlyJob() {
        // Do your job here which should run every hour of day.
    }

    @Schedule(hour="*", minute="*/15", second="0", persistent=false)
    public void someQuarterlyJob() {
        // Do your job here which should run every 15 minute of hour.
    }

    @Schedule(hour="*", minute="*", second="*/5", persistent=false)
    public void someFiveSecondelyJob() {
        // Do your job here which should run every 5 seconds.
    }

} 

Evet, gerçekten hepsi bu. Konteyner otomatik olarak alacak ve yönetecektir.

EJB mevcut değil mi? KullanımScheduledExecutorService

Ortamınız EJB'yi desteklemiyorsa (yani gerçek bir Java EE sunucusu kullanmıyorsanız, Tomcat, Jetty, vb. Gibi bir barebone servlet kapsayıcısı kullanıyorsanız), o zaman kullanın ScheduledExecutorService. Bu, bir ServletContextListener. İşte bir başlangıç ​​örneği:

@WebListener
public class BackgroundJobManager implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
        scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
        scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
        scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        scheduler.shutdownNow();
    }

}

Meslek sınıflarının şöyle göründüğü yer:

public class SomeDailyJob implements Runnable {

    @Override
    public void run() {
        // Do your daily job here.
    }

}
public class SomeHourlyJob implements Runnable {

    @Override
    public void run() {
        // Do your hourly job here.
    }

}
public class SomeQuarterlyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}
public class SomeFiveSecondelyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}

Hiç kullanarak düşünme java.util.Timer/ java.lang.ThreadJava EE / Servlet tabanlı ortamda

Son olarak, hiçbir zaman doğrudan java.util.Timerve / veya java.lang.ThreadJava EE'de kullanmayın. Bu bela için reçetedir. Aynı soruya ilişkin bu JSF ile ilgili yanıtta ayrıntılı bir açıklama bulunabilir: Bir zamanlayıcı kullanarak zamanlanmış görevler için JSF tarafından yönetilen bir çekirdekte ileti dizileri üretme .


9
@BalucS Teşekkür ederim efendim, çözümünüz bana yardımcı oldu ve Java'da yeni olduğum için benim için yeni olan ScheduledExecutorService'i öğrendim. Bir kez daha teşekkür ederim.
pritsag

@BalusC: UpdateCounts sınıfı web.xml'de nereye yerleştirilmelidir?
Ashwin

1
@Ashwin web.xml bir Dağıtım Tanımlayıcısıdır . UpdateCount sınıfı dağıtımla ilgili değildir, bu nedenle web.xml'ye
informatik01

12
A ile ilgili çok önemli bir sorun ScheduledExecutorService: Uygulayıcınızdaki tüm istisnaları yakaladığınızdan emin olun . runYönteminizden bir istisna kaçarsa , yürütücü sessizce yürütmeyi durdurur. Bu bir özelliktir, hata değildir. Belgeyi okuyun ve biraz googling ile çalışın.
Basil Bourque

1
@Agi: Örneğe göre scheduler.shutdownNow()doğru şekilde çağrılmazsa bu olur . Bu çağrılmazsa, zamanlama iş parçacığı gerçekten çalışmaya devam edecektir.
BalusC

4

Görevi düzenli aralıklarla çalıştırmak için kuvars gibi bir kitaplık kullanmanızı öneririm. Servlet gerçekten ne yapıyor? Size bir rapor mu gönderiyor?


evet, bana günlük olarak oluşturulan kullanıcı sayısını ve ayrıca veritabanımdaki toplam kullanıcı sayısını veriyor.
pritsag

1
huuu? Sisteminizin TAM mimarisini tanımlayabilir misiniz? Kayboldum.
Twister

@Twister java için yeniyim ve öğrenme aşamasında efendim ve gerçekten servletler hakkında pek bir şey bilmiyorum.
pritsag

Sorun servlet ile ilgili değil. Bahsettiğiniz uygulama nedir? : (ps özellikle ben cevap yorumlar, yorumlarınızı silmek için kötü bir fikir)
Twister

@ twister, kullanıcı uygulamaya ne zaman vuracaksa, bugün ne kadar kullanıcı oluşturulmuş, şimdiye kadar ne kadar kullanıcı craeted gibi tüm detayları alacaktır ve kullanıcının güncellemeleri alabilmesi için arka planda çalışan sunucu uygulamasını sürekli çalıştırmak istiyorum. Bunun doğru bir açıklama olmadığını biliyorum. (Ps: Bunun kötü bir fikir olduğunu biliyorum. Bunun için üzgünüm.)
pritsag

3

İki sınıfları uygulamak ve çağrı startTask()içinde main.

public void startTask()
{
    // Create a Runnable
    Runnable task = new Runnable() {
        public void run() {
            while (true) {
                runTask();
            }
        }
    };

    // Run the task in a background thread
    Thread backgroundThread = new Thread(task);
    // Terminate the running thread if the application exits
    backgroundThread.setDaemon(true);
    // Start the thread
    backgroundThread.start();
}

public void runTask()
{
    try {
        // do something...         
        Thread.sleep(1000);

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

3
Bu kesinlikle bir web uygulamasında bunu yapmanın yolu DEĞİL - bunun yerine @BalusC'nin yukarıdaki cevabına bakın - burada haklı ve tüm cevaplarına güvenebileceğinizi söyleyebilirim.
Yoshiya


0

Birden fazla jee olmayan konteynerin çalıştığı bir üretim sisteminde. Görev maamgememt için bir veritabanı kullanmak üzere yapılandırılabilen Quartz zamanlayıcı gibi bir kurumsal zamanlayıcı kullanın.

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.