2016-03-08 62 views
5

我有一個在Spring Boot 1.2.3下運行的應用程序,它使用的方法註解爲@Async。迄今爲止它一直在正常工作。升級到Spring Boot後@Async不工作1.3.3

升級到Spring Boot 1.3.3後,標記爲@Async的方法不會在單獨的線程中調用。

下面是說明了問題的一個範例程序:

App.java:

package test; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.CommandLineRunner; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.scheduling.annotation.EnableAsync; 


@Configuration 
@EnableAutoConfiguration 
@ComponentScan(basePackages = { "test" }) 
@EnableAsync 
public class App implements CommandLineRunner { 

    private static final Logger log = LoggerFactory.getLogger(App.class); 

    @Autowired 
    AsyncClass async; 

    public static void main(String[] args) { 
     SpringApplication.run(App.class, args); 
    } 

    public void run(String... arg0) throws Exception { 
     log.info("in run"); 
     async.start(); 
     log.info("done run"); 
    } 

} 

AsyncClass.java:

package test; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.context.annotation.Bean; 
import org.springframework.scheduling.annotation.Async; 
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 
import org.springframework.stereotype.Component; 


@Component 
public class AsyncClass { 

    private static final Logger log = LoggerFactory.getLogger(AsyncClass.class); 

    @Async("myTaskExecutor") 
    public void start() { 
     log.info("in async task"); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { } 
     log.info("done async task"); 
    } 

    @Bean 
    public ThreadPoolTaskExecutor myTaskExecutor() { 

     ThreadPoolTaskExecutor bean = new ThreadPoolTaskExecutor(); 
     bean.setCorePoolSize(1); 
     bean.setMaxPoolSize(1); 
     bean.setQueueCapacity(10); 
     bean.setThreadPriority(1); 
     bean.setWaitForTasksToCompleteOnShutdown(true); 
     return bean; 
    } 

} 

的pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>dbush</groupId> 
    <artifactId>async-test</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <name>async-test</name> 

    <properties> 
     <java.version>1.8</java.version> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 
     <maven.compiler.source>${java.version}</maven.compiler.source> 
     <maven.compiler.target>${java.version}</maven.compiler.target>  
    </properties> 

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <!-- this is the only line that differs --> 
     <version>1.3.3.RELEASE</version> 
    </parent> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
      <exclusions> 
       <exclusion> 
        <groupId>org.slf4j</groupId> 
        <artifactId>log4j-over-slf4j</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 
    </dependencies> 

</project> 

在1.2.3下,日誌start方法中的語句顯示它們在線程myTaskExecutor-1中運行。在1.3.3下,相同的日誌顯示它們在線程main中運行。

任何想法可能是錯誤的嗎?

回答

2

您需要將您的bean工廠方法放在註釋爲@Configuration的其他類中。 Executor將以這種方式用於@Async方法的執行。

@Configuration 
@EnableAsync 
public class AsyncConfig { 
    @Bean(name = "myTaskExecutor") 
    public ThreadPoolTaskExecutor myTaskExecutor() { 
     return new ThreadPoolTaskExecutor(); 
    } 
} 
2

注入配置類可能是一個挑戰,我不會推薦它,特別是如果該類也是一個實際的bean。恕我直言,你的班級確實太多了。接下來移動它所屬的ThreadPoolTaskExecutor的配置。

而不是自動裝配創建一個@Bean方法,它將返回CommandLineRunner而不是您實現它。

@SpringBootApplication 
@EnableAsync 
public class App { 

    private static final Logger log = LoggerFactory.getLogger(App.class); 

    public static void main(String[] args) { 
     SpringApplication.run(App.class, args); 
    } 

    @Bean 
    public CommandLineRunner runner(AsyncClass async) { 

     return new CommandLineRunner() { 
     public void run(String... arg0) throws Exception { 
      log.info("in run"); 
      async.start(); 
      log.info("done run"); 
     }  
     }; 

    } 

    @Bean 
    public ThreadPoolTaskExecutor taskExecutor() { 

     ThreadPoolTaskExecutor bean = new ThreadPoolTaskExecutor(); 
     bean.setCorePoolSize(1); 
     bean.setMaxPoolSize(1); 
     bean.setQueueCapacity(10); 
     bean.setThreadPriority(1); 
     bean.setWaitForTasksToCompleteOnShutdown(true); 
     return bean; 
    } 
} 

然後清理你的AsyncClass

+0

謝謝。這個設置可以在一個簡單的例子中用一個在啓動時啓動的線程來工作,但是完整的程序包含了其中的一個以及通過Web請求調用的第二個任務,所以將'ThreadPoolTask​​Executor' bean放入它們自己的' @ Configuration'類是最簡單的解決方案。 – dbush

相關問題