Java Spring @tâches Planifiées de l'exécution de deux fois
j'ai une méthode d'essai simple ici qui est réglée pour fonctionner toutes les 5 secondes et il le fait, mais en regardant le système.dehors, vous pouvez voir qu'il 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 (apparaissent) à chaque fois?
17 réponses
Si vous regardez la documentation, il y a une note qui appelle explicitement ce phénomène.
la note se trouve sous section 25.5.1 à ce lien , et se lit comme suit:
assurez-vous que vous n'initialisez pas plusieurs instances de la même classe d'annotation @Scheduled à l'exécution, à moins que vous ne vouliez programmer des callbacks pour chacune de ces instances. À cet égard, assurez-vous que vous n'utilisez pas @Configurable sur les classes de haricots qui sont annotés avec @programmable et enregistrés comme des haricots de printemps réguliers avec le conteneur: vous obtiendriez une double initialisation sinon, une fois à travers le conteneur et une fois à travers l'aspect @Configurable, avec la conséquence de chaque méthode @Programmable être invoquée deux fois.
je comprends qu'il s'agit simplement d'une suggestion à ce stade, mais je ne pense pas que nous ayons assez d'information pour diagnostiquer la question plus avant.
je connais la réponse!!
Ne pas init votre Prévues deux fois
Butin à votre web journal :
WebApplicationContext
une fois et servlet une fois
donc dans votre servlet.xml
ne faites pas comme ça
import resource="classpath:applicationContext.xml"
il se passe en raison de l'auditeur de contexte
Juste enlever
< listener >
< listener-class >org.springframework.Web.cadre.ContextLoaderListener< / listener-class >
< / listener >
de web.xml, il doit travailler.
j'ai rencontré un problème similaire. Il pourrait être à cause de raisons ci-dessous.
-
un bug dans les versions de printemps https://jira.spring.io/browse/SPR-10830
-
contexte étant chargé deux fois.
-
le log4j.xml j'écris les journaux deux fois. C'est arrivé dans mon cas, pas sûr que la vôtre. Si vous avez essayé les autres options, essayez celui-ci également.
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 le démarrage à ressort. 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
}
j'ai eu ce même problème, et j'ai finalement découvert que le problème est survenu suite à des grains en cours de création dans le root context
ainsi que le servlet context
.
donc, pour corriger cela, vous devez séparer la création des haricots dans les contextes appropriés.
Cette réponse , explique vraiment bien comment, à qui et ce qui a été corrigé mon problème.
j'ai eu le même problème. Passé des heures à essayer de résoudre.
La Solutionétait que L'application était déployée deux fois sur Tomcat.
en essayant de nettoyer Tomcat il a donné une erreur.
vérification du serveur.j'ai remarqué que le même fichier Tomcat était déployé deux fois. Il y avait aussi une étiquette "hôte" non fermée. Vous ne savez pas lequel de ces fixe, mais soulagé d'avoir fonctionner de nouveau correctement.
j'utilise spring 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é un enregistrement D'INFO disant qu'aucun haricot nommé taskScheduler n'a trouvé, créant une nouvelle instance. Donc, je disais qu'il y avait deux instance de la taskScheduler.
Laissez-moi savoir si cela fonctionne pour vous aussi :)
Eh bien, dans mon cas, le travail avait une annotation @Component et j'avais ceci dans mon contexte d'application.xml:
<task:annotation-driven/>
<bean id="getxxx" class="com.kitar.xxxx.jobs.RomeExample"></bean>
donc la solution est de supprimer la définition de la fève (la deuxième ligne) parce que:
<task:annotation-driven/>
: permet la détection d'annotations @Async et @Scheduled sur n'importe quel objet géré par ressort de sorte qu'il n'est pas nécessaire de définir le travail ou il sera appelé deux fois.
vous pourriez vouloir vérifier si vous scannez des composants pour le même paquet dans deux contextes différents si votre application est WEB, par exemple applicationContext.xml, puis de nouveau quelques-servlet.XML.
<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 ma toile.XML. Donc , vous pouvez voir que "/WEB-INF/spring/appServlet/printemps-contexte.xml" est chargé deux fois (une fois dans context-param , une fois dans servlet -> init-param ).
j'ai fait face à la même situation et résolu par ceci:
1) Service D'Ordonnanceur
@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?");
}
}
j'ai eu le même problème aujourd'hui.
dans mon projet j'utilisais le scheduler avec mon application de démarrage à ressort et dans ma classe Schedlinedtaks j'utilisais l'annotation @Component. Mais j'ai fait une erreur parce que le @ Component représente un haricot pour ma classe et dans ma classe D'Application j'ai créé un autre haricot pour cette classe avec le code:
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Bean
public ScheduledTasks getScheduledTasks() {
return new ScheduledTasks();
}
}
je viens de supprimer cette annotation et le planificateur fonctionne percectly.
Suivre l'exemple de mon code ScheduledTasks classe:
public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(cron = "00 14 11 * * *")
public void reportCurrentTime() {
log.info("The date is: {} " + dateFormat.format(new Date()) );
}
}
et le résultat:
2016-10-20 11:13:41.298 INFO 6832 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-10-20 11:13:41.302 INFO 6832 --- [ main] br.com.Application : Started Application in 9.257 seconds (JVM running for 9.676)
2016-10-20 11:14:00.002 INFO 6832 --- [pool-2-thread-1] br.com.scheduler.ScheduledTasks : The date is: {} 11:14:00
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'ai eu un SpringApplicationBuilder deux fois dans la classe de 2 diferents
dans la demande.propriétés, ajouter la propriété suivante qui indique à L'Application D'amorçage de printemps de ne pas commencer la tâche de lot au démarrage de L'Application.
spring.batch.job.enabled=false
j'ai eu le même problème. J'utilisais la configuration basée sur l'annotation comme suit:
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Scheduled(fixedDelay = 60 * 1000)
public void scheduledJob() {
// this method gets called twice...
}
}
j'étendais aussi AbstractAnnotationConfigDispatcherservletinitializer pour initialiser le même.
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 };
}
}
la suppression de la méthode SchedulerConfig.class
de la méthode getRootConfigClasses()
a fait l'affaire pour moi.
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { MainConfig.class };
}
j'espère que cela aidera.