升级到Spring Boot 1.3.3后,@ Async无法正常工作

时间:2016-03-08 21:26:48

标签: java spring asynchronous spring-boot

我有一个在Spring Boot 1.2.3下运行的应用程序,它使用注释为@Async的方法。到目前为止,它一直在正常工作。

升级到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 个答案:

答案 0 :(得分:2)

您需要将bean工厂方法放在另一个注释为@Configuration的类中。 Executor将以这种方式用于@Async方法执行。

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

答案 1 :(得分: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