ilo*_*una 6 spring asynchronous cglib spring-java-config spring-async
为异步方法提供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;
}
Run Code Online (Sandbox Code Playgroud)
我所有的@Async方法按预期工作,但如果我执行AsyncConfigurer到AsyncConfiguration为了赶实施异常getAsyncUncaughtExceptionHandler()的方法,我的豆子没有被代理这样的方法@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();
}
Run Code Online (Sandbox Code Playgroud)
可能会发生什么?
我们这样使用@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);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我已经提交了一个错误报告(SPR-14630)。
我几乎要向Spring的问题跟踪器提交错误报告,但是当我准备一个用于再现该错误的小型应用程序时,我发现并解决了该问题。
首先,使用时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;
}
Run Code Online (Sandbox Code Playgroud)
同样由于某种原因,如果我@PostConstruct在同一配置类中定义的方法中使用bean ,它将不会异步运行。原因是,该@PostConstruct方法之前执行getAsyncExecutor()和getAsyncUncaughtExceptionHandler()正在执行:
AsyncBean.java:@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);
}
}
Run Code Online (Sandbox Code Playgroud)
AsyncDemoApp.java:@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();
}
}
Run Code Online (Sandbox Code Playgroud)
AsyncDemoApp.start
My name is AsyncBean and I am running in Thread[main,5,main]
AsyncDemoApp.getAsyncExecutor
AsyncDemoApp.getAsyncUncaughtExceptionHandler
Run Code Online (Sandbox Code Playgroud)
但是,如果在准备使用应用程序上下文之后使用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();
}
}
Run Code Online (Sandbox Code Playgroud)
另一个奇怪的现象是,如果你自动装配在同一配置类的异步豆,之前配置的自定义异步执行,因此豆不会异步运行,并在主线程运行自动布线正在发生的事情。这可以通过添加验证@PostConstruct到AsyncBean并使用CommandLineRunner运行应用程序(我个人认为这是一个错误的行为是非常惊人的,至少可以说。):
AsyncBean与@PostConstruct:@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");
}
}
Run Code Online (Sandbox Code Playgroud)
AsyncDemoApp实施CommandLineRunner:@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();
}
}
Run Code Online (Sandbox Code Playgroud)
AsyncBean is constructed
AsyncDemoApp.getAsyncExecutor
AsyncDemoApp.getAsyncUncaughtExceptionHandler
AsyncDemoApp.run
My name is AsyncBean and I am running in Thread[main,5,main]
Run Code Online (Sandbox Code Playgroud)
还有一件事!:)如果使用ThreadPoolTaskExecutor,根据您的要求,可能需要将其daemon属性设置为true,否则您的应用程序将永远运行(这对于Web / Worker应用程序来说不是大问题)。这是JavaDoc setDaemon(boolean)所说的:
设置该工厂是否应该创建守护程序线程,只要应用程序本身正在运行就执行。默认值为“ false”:具体工厂通常支持显式取消。因此,如果应用程序关闭,Runnables将默认完成其执行。将“ true”指定为急切关闭仍在应用程序本身关闭时仍在主动执行Runnable的线程。
| 归档时间: |
|
| 查看次数: |
6362 次 |
| 最近记录: |