2013-01-09 130 views
24

我有一个简单的测试方法,它设置为每5秒运行一次,但是看看System.out,你会发现它看起来很奇怪。Java Spring @计划任务执行两次

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

为什么两次,每次时间(出现)运行?

+1

您正在运行哪个版本的Spring?你确定你没有加载上下文两次,导致创建两个调度程序线程。 – Swapnil

+0

在创建类的实例时尝试记录 –

回答

19

如果你看一下文档,有一个注释明确地提出这种现象。

说明是section 25.5.1 at this link下,并写着:

确保您不会在运行时初始化同一@Scheduled注解类的多个实例,除非你想安排回调到每一个这样的实例。与此相关的是,请确保您没有在@Scheduled注释的bean类上使用@Configurable,并将其注册为具有容器的常规Spring bean:否则,您将获得双重初始化,否则一旦通过容器并通过@Configurable方面,每个@Scheduled方法的结果被调用两次。

据我所知,这只是在这一点上的建议,但我认为我们没有足够的信息来进一步诊断问题。

+1

好的,那么究竟应该在哪个类中声明预定的方法?如果我在用@Service注解的类中使用它,我得到这种行为/ – demaniak

+0

在我的情况下,我想用@WebServlet – ropo

3

我知道答案!

不要在你的网络日志初始化你计划的两倍

战利品:

WebApplicationContext一次和servlet一次

所以在你的servlet.xml不要做这样的

import resource="classpath:applicationContext.xml" 
5

这是因为上下文听众发生的

只是删除

<听者>

<监听级> org.springframework.web.context.ContextLoaderListener < /监听级>

< /监听>

从网页。它应该工作的XML。

+35

手动调用预定的函数就像删除system32以使计算机运行得更快一样? – Matthew

+0

Hello Girish,我从web.xml中删除了这段代码,我的spring @Scheduled开始工作,但是我的是Spring MVC应用程序。当我尝试在其上运行index.jsp时。它显示我错误:没有找到WebApplicationContext:没有ContextLoaderListener注册?这是什么解决方案? –

+2

@Matthew您的评论使我的一天! –

0

我使用弹簧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豆发现,创建一个新的实例。所以我觉得有两个taskScheduler的实例。

让我知道,如果这也适用于你:)

在我的情况下工作的豆有@Component注释和我有这个在我的applicationContext.xml
0

好:

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

所以解决方法是删除bean定义(第二行),因为:

<task:annotation-driven/>:允许在任何Spring管理的对象上检测@Async和@Scheduled注释,因此不需要defi在作业的bean中,它将被调用两次。

2

我遇到了类似的问题。这可能是因为以下原因。

  1. 中的错误在弹簧版本 https://jira.spring.io/browse/SPR-10830

  2. 上下文被加载两次。

  3. log4j.xml两次写入日志。在我的情况发生了不知道你的。如果您尝试了其他选项,请尝试使用其他选项。

0

如果您的应用程序是WEB,您可能需要检查是否在两个不同的上下文中扫描相同程序包的组件。 applicationContext.xml,然后再some-servlet.xml。

0

我有这个相同的问题,我最终发现问题是由于在root context以及servlet context中创建的bean的结果而发生的。

因此,要解决这个问题,您需要将bean的创建分离到适当的上下文中。

This answer很好的解释了如何解决问题。

0
<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”加载了两次(一次在context-param中,一次在servlet - > init-param中)。

0

我已经通过这个面临着同样的情况,并解决:

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

今天我有同样的问题。

在我的项目中,我使用了我的弹簧启动应用程序的调度程序,在我的ScheduledTaks类中,我使用了@Component注释。但我犯了一个错误,因为@Component代表一个bean我的课,在我的应用程序类,我有这个类的代码创建另一个bean:

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

我刚刚删除此注释和调度工作percectly。

按照我的代码ScheduledTasks类的例子:

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

而结果:

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 
2

我有一个类似的问题,我解决我的这样做:

package com.sample.config; 

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

@Configuration 
@EnableScheduling 
public class JobExecutorConfig { 
} 

作为弹簧引导的配置。我添加这个作为工作类:

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

我有同样的问题。花费数小时试图解决。

解决方案是应用程序在Tomcat上部署两次。

当试图清理Tomcat时,它给出了一个错误。

检查server.xml Tomcat文件我注意到同样的部署两次。还有一个未封闭的“主机”标签。不知道这些固定它,但松了一口气,让它再次正常工作。

+0

在我的情况下,这是由于Idea部署中配置错误,因此在weblogic上进行双重部署。 –