首页 文章

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

提问于
浏览
6

我有一个在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 回答

  • 2

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

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

    注入配置类可能是一个挑战,我不推荐它,特别是如果该类也是一个实际的bean . 恕我直言你的 class 做得太多了 . 接下来移动它所属的 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 .

相关问题