2013-01-09 128 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上進行雙重部署。 –