Spring异步不';实现AsyncConfigurer时无法工作

Spring异步不';实现AsyncConfigurer时无法工作,spring,asynchronous,spring-java-config,cglib,spring-async,Spring,Asynchronous,Spring Java Config,Cglib,Spring Async,将异步方法的Spring配置类设置为: @Configuration @EnableAsync(proxyTargetClass = true) @EnableScheduling public class AsyncConfiguration { @Autowired private ApplicationContext applicationContext; @Bean public ActivityMessageListener activityMessageListener() {

将异步方法的Spring配置类设置为:

@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
public class AsyncConfiguration {

@Autowired
private ApplicationContext applicationContext;

@Bean
public ActivityMessageListener activityMessageListener() {
    return new ActivityMessageListener();
}
@Bean
public TaskExecutor defaultExecutor()
{
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
    threadPoolTaskExecutor.setCorePoolSize(10);
    threadPoolTaskExecutor.setMaxPoolSize(10);
    threadPoolTaskExecutor.setQueueCapacity(Integer.MAX_VALUE);

    return threadPoolTaskExecutor;
}
我所有的
@Async
方法都按预期工作,但是如果我将
AsyncConfigurer
实现为
AsyncConfiguration
以捕获实现
getAsyncUncaughtExceptionHandler()
方法的异常,我的bean不会被代理,因此方法
@Async
不会在池执行器中运行

这是非工作配置:

@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {

@Autowired
private ApplicationContext applicationContext;

@Bean
public ActivityMessageListener activityMessageListener() {
    return new ActivityMessageListener();
}

@Override
public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
    threadPoolTaskExecutor.setCorePoolSize(10);
    threadPoolTaskExecutor.setMaxPoolSize(10);
    threadPoolTaskExecutor.setQueueCapacity(Integer.MAX_VALUE);

    return threadPoolTaskExecutor;
}

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler()        {
    return new SimpleAsyncUncaughtExceptionHandler();
}
会发生什么

我们使用的
@Async
如下:

public class ActivityMessageListener extends BaseMessageListener {

public static final String PARAM_USER_ID                = "userId";
public static final String PARAM_COMPANY_ID             = "companyId";
public static final String PARAM_CREATE_DATE            = "createDate";
public static final String PARAM_CLASS_NAME             = "className";
public static final String PARAM_CLASS_PK               = "classPK";
public static final String PARAM_TYPE                   = "type";
public static final String PARAM_EXTRA_DATA             = "extraData";
public static final String PARAM_RECEIVED_USER_ID       = "receiverUserId";

@Override @Async(value = "defaultExecutor")
public Future<String> doReceive(Message message) throws Exception {

    String name = Thread.currentThread().getName();
    Map<String, Object> parameters  = message.getValues();
    Long userId                     = (Long)parameters.get(ActivityMessageListener.PARAM_USER_ID);
    Long companyId                  = (Long)parameters.get(ActivityMessageListener.PARAM_COMPANY_ID);
    Date createDate                 = (Date)parameters.get(ActivityMessageListener.PARAM_CREATE_DATE);
    String className                = (String)parameters.get(ActivityMessageListener.PARAM_CLASS_NAME);
    Long classPK                    = (Long)parameters.get(ActivityMessageListener.PARAM_CLASS_PK);
    Integer type                    = (Integer)parameters.get(ActivityMessageListener.PARAM_TYPE);
    String extraData                = (String)parameters.get(ActivityMessageListener.PARAM_EXTRA_DATA);
    Long receiverUserId             = (Long)parameters.get(ActivityMessageListener.PARAM_RECEIVED_USER_ID);
    ActivityLocalServiceUtil.addActivity(userId, companyId, createDate, className, classPK, type, extraData, receiverUserId);

    return new AsyncResult<String>(name);
}
}
公共类ActivityMessageListener扩展了BaseMessageListener{
公共静态最终字符串PARAM_USER_ID=“userId”;
公共静态最终字符串PARAM_COMPANY_ID=“companyId”;
公共静态最终字符串PARAM_CREATE_DATE=“createDate”;
公共静态最终字符串PARAM_CLASS_NAME=“className”;
公共静态最终字符串PARAM_CLASS_PK=“classPK”;
公共静态最终字符串PARAM_TYPE=“TYPE”;
公共静态最终字符串PARAM_EXTRA_DATA=“extraData”;
公共静态最终字符串PARAM_RECEIVED_USER_ID=“receiverUserId”;
@重写@Async(value=“defaultExecutor”)
公共未来数据接收(消息)引发异常{
字符串名称=Thread.currentThread().getName();
映射参数=message.getValues();
Long userId=(Long)parameters.get(ActivityMessageListener.PARAM_USER_ID);
Long companyId=(Long)parameters.get(ActivityMessageListener.PARAM_COMPANY_ID);
Date createDate=(Date)parameters.get(ActivityMessageListener.PARAM_CREATE_Date);
String className=(String)parameters.get(ActivityMessageListener.PARAM_CLASS_NAME);
Long classPK=(Long)parameters.get(ActivityMessageListener.PARAM_CLASS_PK);
整数类型=(整数)参数.get(ActivityMessageListener.PARAM_类型);
String extraData=(String)parameters.get(ActivityMessageListener.PARAM_EXTRA_DATA);
Long receiverUserId=(Long)parameters.get(ActivityMessageListener.PARAM_RECEIVED_USER_ID);
ActivityLocalServiceUtil.addActivity(userId、companyId、createDate、className、classPK、type、extraData、receiverUserId);
返回新的异步结果(名称);
}
}

编辑:我已经提交了一份文件


我即将向Spring提交一份bug报告,但是当我准备一个复制bug的小应用程序时,我发现并修复了这个问题

首先,在使用
ThreadPoolTaskExecutor
时,应在返回它之前调用它的
initialize()
方法:

@Override
public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setMaxPoolSize(1);
    executor.setCorePoolSize(1);
    executor.setThreadNamePrefix("CUSTOM-");

    // Initialize the executor
    executor.initialize();

    return executor;
}
同样出于某种原因,如果我在同一配置类中定义的
@PostConstruct
方法中使用bean,它将不会异步运行。原因是
@PostConstruct
方法在执行
getAsyncExecutor()
getAsyncUncaughtExceptionHandler()
之前执行:

AsyncBean.java
AsyncDemoApp.java
: 输出: 但是,如果您在应用程序上下文准备好使用后使用bean,那么它应该可以按预期工作:

@SpringBootApplication
@EnableAsync
public class AsyncDemoApp implements AsyncConfigurer {

    public static void main(String[] args) {
        final ConfigurableApplicationContext context = SpringApplication.run(AsyncDemoApp.class, args);

        final IAsyncBean asyncBean = context.getBean(IAsyncBean.class);

        asyncBean.whoAmI();
    }

    @Override
    public Executor getAsyncExecutor() {
        System.out.println("AsyncDemoApp.getAsyncExecutor");

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("CUSTOM-");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        System.out.println("AsyncDemoApp.getAsyncUncaughtExceptionHandler");
        return (throwable, method, objects)
                -> throwable.printStackTrace();
    }
}
另一个奇怪的行为是,如果在同一个配置类中自动连接异步bean,则自动连接是在配置自定义异步执行器之前发生的,因此bean不会异步运行,而是在主线程中运行。这可以通过将
@PostConstruct
添加到
AsyncBean
并使用
CommandLineRunner
运行应用程序来验证(我个人认为这是一个bug。至少可以说,其行为非常令人惊讶):

AsyncBean
@PostConstruct
AsyncDemoApp
实现
CommandLineRunner
: 输出:
还有一件事!:)如果您使用
ThreadPoolTaskExecutor
,根据您的需求,您可能希望将其守护程序属性设置为true,否则您的应用程序将永远运行(这对于Web/Worker应用程序来说不是大问题)。下面是
setDaemon(布尔值)
的JavaDoc所说的:

设置此工厂是否应该创建守护进程线程,只需 只要应用程序本身在运行,就可以执行。默认为 “错误”:混凝土工厂通常支持明确取消。 因此,如果应用程序关闭,Runnables将默认完成 他们的死刑。指定“true”用于紧急关闭 仍然在应用程序运行时主动执行Runnable 自动关闭


因为它是一个配置时间类,不应该由实际的异步类实现,它们是用于配置异步处理的。对不起,我不明白,你能扩展你的答案吗?
AsyncConfigurer
如果要配置你的异步基础设施,它应该由配置bean而不是服务bean来实现。啊,好的,是的,这就是我要做的,当我更改
AsyncConfiguration
以实现
AsyncConfigurer
然后发布该配置而不是非工作配置时,就会出现问题。请添加您尝试过的内容。非常感谢。我使用您的想法解决我的问题。再次感谢!
@SpringBootApplication
@EnableAsync
public class AsyncDemoApp implements AsyncConfigurer {

    @Autowired
    private IAsyncBean asyncBean;

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

    @Override
    public Executor getAsyncExecutor() {
        System.out.println("AsyncDemoApp.getAsyncExecutor");

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("CUSTOM-");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        System.out.println("AsyncDemoApp.getAsyncUncaughtExceptionHandler");
        return (throwable, method, objects)
                -> throwable.printStackTrace();
    }

    @PostConstruct
    public void start() {
        System.out.println("AsyncDemoApp.start");
        asyncBean.whoAmI();
    }
}
AsyncDemoApp.start
My name is AsyncBean and I am running in Thread[main,5,main]
AsyncDemoApp.getAsyncExecutor
AsyncDemoApp.getAsyncUncaughtExceptionHandler
@SpringBootApplication
@EnableAsync
public class AsyncDemoApp implements AsyncConfigurer {

    public static void main(String[] args) {
        final ConfigurableApplicationContext context = SpringApplication.run(AsyncDemoApp.class, args);

        final IAsyncBean asyncBean = context.getBean(IAsyncBean.class);

        asyncBean.whoAmI();
    }

    @Override
    public Executor getAsyncExecutor() {
        System.out.println("AsyncDemoApp.getAsyncExecutor");

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("CUSTOM-");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        System.out.println("AsyncDemoApp.getAsyncUncaughtExceptionHandler");
        return (throwable, method, objects)
                -> throwable.printStackTrace();
    }
}
@Component
public class AsyncBean implements IAsyncBean {

    @Override
    @Async
    public void whoAmI() {
        final String message =
                String.format("My name is %s and I am running in %s", getClass().getSimpleName(), Thread.currentThread());

        System.out.println(message);
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("AsyncBean is constructed");
    }
}
@SpringBootApplication
@EnableAsync
public class AsyncDemoApp implements AsyncConfigurer, CommandLineRunner {

    @Autowired
    private IAsyncBean asyncBean;

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

    @Override
    public Executor getAsyncExecutor() {
        System.out.println("AsyncDemoApp.getAsyncExecutor");

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("CUSTOM-");
        executor.initialize();

        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        System.out.println("AsyncDemoApp.getAsyncUncaughtExceptionHandler");
        return (throwable, method, objects)
                -> throwable.printStackTrace();
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("AsyncDemoApp.run");
        asyncBean.whoAmI();
    }
}
AsyncBean is constructed
AsyncDemoApp.getAsyncExecutor
AsyncDemoApp.getAsyncUncaughtExceptionHandler
AsyncDemoApp.run
My name is AsyncBean and I am running in Thread[main,5,main]