web-dev-qa-db-fra.com

Java Spring @ Tâches planifiées exécutées deux fois

J'ai une méthode de test simple ici qui est configurée pour s'exécuter toutes les 5 secondes et c'est le cas, mais en regardant System.out, vous pouvez voir qu'elle semble faire quelque chose de bizarre.

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

Sortie:

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

Pourquoi tourne-t-il DEUX FOIS (apparaît) à chaque fois?

27
Casper

Si vous regardez la documentation, une note appelle explicitement ce phénomène.

La note est sous section 25.5.1 à ce lien , et se lit comme suit:

Assurez-vous de ne pas initialiser plusieurs instances de la même classe d'annotations @Scheduled au moment de l'exécution, sauf si vous souhaitez planifier des rappels pour chacune de ces instances. Dans le même ordre d'idées, veillez à ne pas utiliser @Configurable sur les classes de beans annotées avec @Scheduled et enregistrées comme beans Spring ordinaires avec le conteneur: vous obtiendriez une double initialisation sinon, une fois à travers le conteneur et une fois à travers l'aspect @Configurable , avec pour conséquence que chaque méthode @Scheduled est invoquée deux fois.

Je comprends que ce n’est qu’une suggestion pour le moment, mais je ne pense pas que nous ayons suffisamment d’informations pour diagnostiquer davantage le problème.

21
nicholas.hauschild

Je connais la réponse!!

Ne pas initier votre planifié deux fois 

Butin sur votre journal web:

WebApplicationContext une fois et servlet une fois 

donc dans votre servlet.xml ne faites pas comme ça 

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

il se passe à cause de l'écoute du contexte

Il suffit de retirer 

<auditeur>

<listener-class> org.springframework.web.context.ContextLoaderListener </ listener-class>

</ listener>

de web.xml cela devrait fonctionner.

4
Girish Kumar

J'ai eu un problème similaire, j'ai résolu le mien en faisant ceci:

package com.sample.config;

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

@Configuration
@EnableScheduling
public class JobExecutorConfig {
}

comme configuration pour la botte de printemps. Et j'ajoute ceci comme 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
}
2
ciberkids

J'ai rencontré un problème similaire. Ce pourrait être pour des raisons ci-dessous.

  1. Un bogue dans les versions de printemps https://jira.spring.io/browse/SPR-10830

  2. Le contexte est chargé deux fois. 

  3. Le log4j.xml écrit les journaux deux fois. C'est arrivé dans mon cas, pas sûr de la tienne. Si vous avez essayé les autres options, essayez aussi celle-ci.

2
jchandrra

J'ai eu le même problème et j'ai finalement découvert que le problème était dû aux beans créés dans le root context et le servlet context

Donc, pour résoudre ce problème, vous devez séparer la création des beans dans les contextes appropriés.

Cette réponse explique très bien comment y arriver et a été ce qui a résolu mon problème.

1
jlars62

Selon this post et Spring Jira , il s'agit d'un bogue dans le composant Spring Framework Scheduler.

0
Prashant

J'ai eu le même problème. J'ai passé des heures à essayer de résoudre.

La solution était l'application déployée deux fois sur Tomcat. 

En essayant de nettoyer Tomcat, une erreur s'est produite.

Vérification du fichier server.xml Tomcat J'ai remarqué que la même chose était déployée deux fois. Il y avait aussi une balise "Host" non fermée. Je ne sais pas lequel de ces problèmes a résolu le problème mais soulagé de le faire fonctionner correctement à nouveau.

0
Daryn

j'utilise le printemps 4.0.3 et j'ai ce problème. Je l'ai résolu en renommant mes haricots.

à:

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

J'ai remarqué des traces d'informations indiquant qu'aucun bean nommé taskScheduler n'a été trouvé, ce qui crée une nouvelle instance. J'ai donc pensé qu'il y avait deux instances de la tâche Scheduler.

Faites-moi savoir si cela fonctionne pour vous aussi :)

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

C'est mon web.xml. Ainsi, vous pouvez voir que "/WEB-INF/spring/appServlet/spring-context.xml" est chargé deux fois (une fois dans context-param, une fois dans servlet -> init-param).

0
Ax Constantin

Dans mon cas, le bean du travail avait l'annotation @Component et j'avais ceci dans mon applicationContext.xml: 

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

La solution consiste donc à supprimer la définition du bean (la deuxième ligne) car:

<task:annotation-driven/>: permet la détection des annotations @Async et @Scheduled sur tout objet géré par Spring. Il n'est donc pas nécessaire de définir le bean du travail, sinon celui-ci sera appelé deux fois.

0
Khalil Kitar

J'ai eu le même problème. J'utilisais la configuration basée sur les annotations comme suit:

@Configuration
@EnableScheduling
public class SchedulerConfig {

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

J'étendais également AbstractAnnotationConfigDispatcherServletInitializer pour l'initialiser.

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

}

Supprimer la méthode SchedulerConfig.class de getRootConfigClasses() a été très utile.

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

J'espère que ça aide.

0
Nasir

Vous voudrez peut-être vérifier si vous analysez des composants pour le même package dans deux contextes différents si votre application est Web, par exemple applicationContext.xml, puis à nouveau some-servlet.xml.

0
Bran

J'ai fait face à la même situation et résolu par ceci:

1) service de planificateur

@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) classe ouvrière

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

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

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

}
0
Bahadir Tasdemir

J'ai eu le même problème, en regardant dans mon code et après avoir essayé tout ce qui est ici, j'ai trouvé que j'avais un SpringApplicationBuilder deux fois dans deux classes différentes

0
Chocolim