2016-03-08 31 views
5

私は、アプリケーションがSpringブート1.2.3の下で実行され、@Asyncと注釈されたメソッドを使用しています。今日まで、それは適切に機能しています。Spring Boot 1.3.3にアップグレードした後に@Asyncが動作しない

Springブート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である場合はお勧めできません。 IMHOあなたのクラスはあまりにも多くを行います。その隣にあるThreadPoolTaskExecutorの構成を移動します。

autowiringの代わりに@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

ありがとうございました。この設定は、スタートアップ時に開始するスレッドを使った単純な例では機能しますが、フルプログラムにはこれらのうちの1つとWebリクエストを介して呼び出される2番目のタスクが含まれているので、 'ThreadPoolTask​​Executor' @ Configuration'クラスが最も簡単な解決策でした。 – dbush

関連する問題