web-dev-qa-db-ja.com

Java Spring @Scheduledタスクが2回実行される

ここには、5秒ごとに実行するように設定された簡単なテストメソッドがありますが、System.outを見ると、奇妙なことをしているように見えます。

@Scheduled(cron="*/5 * * * * ?")
public void testScheduledMethod() {
     System.out.println(new Date()+" > Running testScheduledMethod...");
}

出力:

Wed Jan 09 16:49:15 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:15 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:20 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:20 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:25 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:25 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:30 GMT 2013 > Running testScheduledMethod...
Wed Jan 09 16:49:30 GMT 2013 > Running testScheduledMethod...

毎回TWICE (appear)を実行するのはなぜですか?

30
KS1

ドキュメントを見ると、この現象を明示的に示しているメモがあります。

注は このリンクのセクション25.5.1 の下にあり、次のように記載されています。

実行時に同じ@Scheduledアノテーションクラスの複数のインスタンスを初期化していないことを確認してください。ただし、各インスタンスへのコールバックをスケジュールしたい場合を除きます。これに関連して、@ Scheduledアノテーションが付けられ、コンテナを使用して通常のSpring Beanとして登録されているBeanクラスで@Configurableを使用しないようにしてください。 、各@Scheduledメソッドが2回呼び出される結果。

これは現時点での提案にすぎないことを理解していますが、問題をさらに診断するのに十分な情報があるとは思いません。

24

答えを知っている!!

スケジュールを2回初期化しないでください

Webログで略奪する:

WebApplicationContextを1回、サーブレットを1回

あなたのservlet.xmlこのようにしないでください

import resource="classpath:applicationContext.xml"
5
user2408678

コンテキストリスナーが原因で発生しています

削除するだけ

<リスナー>

<リスナークラス> org.springframework.web.context.ContextLoaderListener </ listener-class>

</ listener>

web.xmlから動作するはずです。

3
Girish Kumar

同様の問題が発生しました。以下の理由が考えられます。

  1. 春バージョンのバグ https://jira.spring.io/browse/SPR-108

  2. コンテキストが2回ロードされています。

  3. Log4j.xmlはログを2回書き込みます。私の場合、あなたのものがわからないことが起こりました。他のオプションを試した場合は、これも試してください。

2
jchandrra

私は同様の問題を抱えていたので、これを解決しました:

package com.sample.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration
@EnableScheduling
public class JobExecutorConfig {
}

スプリングブートの構成として。そして、これをjobclassとして追加します。

package com.sample.jobs;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class Job {

  private final Logger log = LoggerFactory.getLogger(this.getClass());

  @Autowired
  MyOtherClass moc;

  @Scheduled(fixedRate = 60000) // every 60 seconds
  public void doJob() {
    log.debug("Job running !!!");
    try {
     moc.doSomething()
    } catch (Exception e) {
      log.error(e.getMessage());
    }
    finally {

      log.debug("job Done !!!");
    }

  }

  // examples of other CRON expressions
  // * "0 0 * * * *" = the top of every hour of every day.
  // * "*/10 * * * * *" = every ten seconds.
  // * "0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
  // * "0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.
  // * "0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
  // * "0 0 0 25 12 ?" = every Christmas Day at midnight
}
1
ciberkids

私はこの同じ問題を抱えていましたが、root contextおよびservlet contextでBeanが作成された結果として問題が発生していることが最終的にわかりました。

したがって、これを修正するには、Beanの作成を適切なコンテキストに分離する必要があります。

この回答 は、その方法を本当によく説明し、私の問題を解決したものでした。

1
jlars62

this postおよび Spring Jira によると、これはSpring Framework Schedulerコンポーネントのバグです。

0
Prashant

同じ問題がありました。解決に時間を費やしました。

解決策は、アプリケーションがTomcatに2回デプロイされていたことです。

Tomcatをクリーニングしようとすると、エラーが発生しました。

Server.xml Tomcatファイルの確認同じことが2回展開されていることに気付きました。閉じられていない「ホスト」タグもありました。これらのどれがそれを修正したかはわかりませんが、再び正常に機能するようになったので安心しました。

0
Daryn

spring 4.0.3を使用していますが、この問題があります。豆の名前を変更して解決しました。

に:

<task:annotation-driven executor="taskExecutor"
    scheduler="taskScheduler" />
<task:executor id="taskExecutor" pool-size="25" />
<task:scheduler id="taskScheduler" pool-size="25" />

TaskSchedulerという名前のBeanが見つからず、新しいインスタンスを作成しているというINFOロギングに気付きました。そこで、taskSchedulerのインスタンスが2つあると考えました。

これがあなたにも役立つかどうか教えてください:)

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
         /WEB-INF/spring/root-context.xml
         /WEB-INF/spring/security/spring-security.xml
         /WEB-INF/spring/mongo/mongo-config.xml
         /WEB-INF/spring/appServlet/spring-context.xml
    </param-value>
</context-param>
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/spring-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

それが私のweb.xmlです。そのため、「/ WEB-INF/spring/appServlet/spring-context.xml」が2回ロードされることがわかります(context-paramで1回、servlet-> init-paramで1回)。

0
Ax Constantin

私の場合、ジョブのBeanには@Componentアノテーションがあり、applicationContext.xmlにこれがありました。

<task:annotation-driven/> <bean id="getxxx" class="com.kitar.xxxx.jobs.RomeExample"></bean>

解決策は、Bean定義(2行目)を削除することです:

<task:annotation-driven/>:ジョブのBeanを定義する必要がないため、Springが管理するオブジェクトで@Asyncおよび@Scheduledアノテーションを検出できるようにします。そうしないと、2回呼び出されます。

0
Khalil Kitar

同じ問題がありました。次のように注釈ベースの構成を使用していました。

_@Configuration
@EnableScheduling
public class SchedulerConfig {

    @Scheduled(fixedDelay = 60 * 1000)
    public void scheduledJob() { 
        // this method gets called twice... 
    }   
}
_

また、AbstractAnnotationConfigDispatcherServletInitializerを初期化するために拡張していました。

_public class SpringWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class<?>[] { MainConfig.class, SchedulerConfig.class };
}

@Override
protected Class<?>[] getServletConfigClasses() {
    return new Class<?>[] {SpringWebConfig.class};
}

@Override
protected String[] getServletMappings() {
    return new String[] { "/" };
}

@Override
protected Filter[] getServletFilters() {
    final CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
    encodingFilter.setEncoding(CHARACTER_ENCODING);
    encodingFilter.setForceEncoding(true);
    return new Filter[] { encodingFilter };
}
_

}

getRootConfigClasses()メソッドから_SchedulerConfig.class_を削除すると、うまくいきました。

_@Override
protected Class<?>[] getRootConfigClasses() {
    return new Class<?>[] { MainConfig.class };
}
_

これがお役に立てば幸いです。

0
Nasir

アプリがWEBの場合、2つの異なるコンテキストで同じパッケージのコンポーネントをスキャンしているかどうかを確認することをお勧めします。 applicationContext.xml、そしてまたsome-servlet.xml。

0
Bran

私は同じ状況に直面し、これによって解決しました:

1)スケジューラーサービス

@Service
public class SchedulerService {

    @Autowired
    @Qualifier("WorkerClass")
    private Worker worker;

    @Scheduled(cron="0/5 * * * * ?", zone="Asia/Colombo")//zone is a sample
    public void doSchedule() {
        worker.work();
    }

}

2)労働者階級

@Component("WorkerClass")
public class WorkerClass implements Worker {

    @Override
    public void work() {
        doSomething();
    }

    protected void doSomething() {
        system.out.pringln("What must I do?");
    }

}
0

私は同じ問題を抱えていて、コードを見て、ここにあるすべてを試した後、2つの異なるクラスにSpringApplicationBuilderが2回あることがわかりました

0
Chocolim