问题
I have a simple test method here that is set to run every 5 seconds and it does, but looking at the System.out you can see it appears to be doing something odd.
@Scheduled(cron="*/5 * * * * ?")
public void testScheduledMethod() {
System.out.println(new Date()+" > Running testScheduledMethod...");
}
Output:
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...
Why is it running TWICE (appear) each time?
回答1:
If you look at the documentation, there is a note that explicitly calls out this phenomenon.
The note is under section 25.5.1 at this link, and reads:
Make sure that you are not initializing multiple instances of the same @Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use @Configurable on bean classes which are annotated with @Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the @Configurable aspect, with the consequence of each @Scheduled method being invoked twice.
I understand that this is merely suggestion at this point, but I do not think we have enough information to diagnose the issue further.
回答2:
I know the answer!!
Don't init your Scheduled twice
Loot at your web log :
WebApplicationContext
once and servlet once
so in your servlet.xml
don't do like this
import resource="classpath:applicationContext.xml"
回答3:
it is happening because of context listener
Just remove
< listener >
< listener-class >org.springframework.web.context.ContextLoaderListener< /listener-class >
< /listener >
from web.xml it should work.
回答4:
I encountered similar problem. It could be because of below reasons.
A bug in spring versions https://jira.spring.io/browse/SPR-10830
Context being loaded twice.
The log4j.xml writing the logs twice. It happened in my case not sure about yours. If you have tried the other options, try this one also.
回答5:
I was declaring my class as a "Service" and also using the @Scheduled annotation to declare it as a Scheduler. The scheduler invokes it normally, but as we declared the class as a service. It was initiated twice.
I removed the Service annotation. And declared that class as a bean in the context XML I have maintained. (custom context XML which is declared in web.xml). This fixed the issue for me. Hope it helps someone.
回答6:
I had this same problem, and I eventually found out that the problem was occurring as a result of the beans being created in the root context
as well as the servlet context
.
So, to fix this, you need to separate the creation of the beans into the appropriate contexts.
This answer explains really well how to that and was what fixed my problem.
回答7:
I had a similar problem, I resolved mine doing this:
package com.sample.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
public class JobExecutorConfig {
}
as configuration for spring boot. And I add this as 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
}
回答8:
i am using spring 4.0.3 and i have this problem. i solved it by renaming my beans.
to:
<task:annotation-driven executor="taskExecutor"
scheduler="taskScheduler" />
<task:executor id="taskExecutor" pool-size="25" />
<task:scheduler id="taskScheduler" pool-size="25" />
I noticed some INFO logging saying that no bean named taskScheduler found, creating a new instance. So I figured there were two instance of the taskScheduler.
Let me know if this works for you too :)
回答9:
Well in my case the job's bean had @Component annotation and i had this in my applicationContext.xml :
<task:annotation-driven/>
<bean id="getxxx" class="com.kitar.xxxx.jobs.RomeExample"></bean>
So the solution is to delete the bean definition (the second line) because :
<task:annotation-driven/>
: allow the detection of @Async and @Scheduled annotations on any Spring-managed object so no need to define the job's bean or it will be called twice.
回答10:
According to this post and Spring Jira this is a bug in Spring Framework Scheduler component.
回答11:
You might want to check if you are scanning components for the same package in two different contexts if your app is WEB, e.g. applicationContext.xml and then again some-servlet.xml.
回答12:
<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>
That is my web.xml . So , you can see that "/WEB-INF/spring/appServlet/spring-context.xml" is loaded twice (once in context-param , once in servlet -> init-param ).
回答13:
I have faced the same situation and solved by this:
1) Scheduler Service
@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) Worker Class
@Component("WorkerClass")
public class WorkerClass implements Worker {
@Override
public void work() {
doSomething();
}
protected void doSomething() {
system.out.pringln("What must I do?");
}
}
回答14:
I had the same problem. Spent hours trying to resolve.
Solution was the application was deploying twice on Tomcat.
When trying to clean Tomcat it gave an error.
Checking the server.xml Tomcat file I noticed the same was being deployed twice. There was also an unclosed "host" tag. Not sure which of these fixed it but relieved to have it working properly again.
回答15:
I did have the same problem, looking in my code and after try all that is here, I did find that I had a SpringApplicationBuilder twice in 2 diferents class
回答16:
I had the same problem. I was using annotation based configuration as follows:
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Scheduled(fixedDelay = 60 * 1000)
public void scheduledJob() {
// this method gets called twice...
}
}
I was also extending AbstractAnnotationConfigDispatcherServletInitializer for initializing the same.
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 };
}
}
Removing the SchedulerConfig.class
from getRootConfigClasses()
method did the trick for me.
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { MainConfig.class };
}
I hope this helps.
回答17:
I had the same problem, I tried all the suggested methods and nothing worked for me. Finally I was able to find the solution by removing the extension to 'SpringBootServletInitializer' and the 'configure' method of my WebApplication class and with this I stopped duplicating my Scheduled Task.
回答18:
I had the same problem today.
In my project i was using the scheduler with my spring boot application and in my ScheduledTaks class i was using the @Component annotation. But i made a mistake because the @Component represent a bean for my class and in my Application class i have create another bean for this class with the 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();
}
}
I just remove this annotation and the scheduler works percectly.
Follow the example of my code ScheduledTasks class:
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()) );
}
}
And the result:
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
回答19:
In the application.properties, add the following property which tells the Spring Boot Application to not start the Batch Job on Application startup.
spring.batch.job.enabled=false
回答20:
Had the same problem.
In my case I moved my @Scheduled functions from @Service into new separate class with @Component annotation and it fixed my problem
来源:https://stackoverflow.com/questions/14242310/java-spring-scheduled-tasks-executing-twice