leftso 1705 0 2018-04-04 21:14:10

文章位置:左搜> 编程技术> 正文

引言

在这篇文章中,我们将讨论有关使用异步任务执行程序功能在不同线程中执行任务的Spring boot 异步执行支持。我们将看看在Spring项目中配置SimpleAsyncTaskExecutorConcurrentTaskExecutorThreadPoolExecutor。除此之外,我们还将研究在Spring中处理异步行为时如何将实际方法返回类型封装到Future对象中。因此,让我们开始使用Spring boot异步任务执行器。

Spring中异步的配置

要在Spring中启用异步行为,请使用@EnableAsync注释您的配置类。
 

@EnableAsync 
@SpringBootApplication 
public class Application {

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

@EnableAsync:它检测@Async注释。

模式 - mode()属性控制如何应用建议。默认情况下,它的值是AdviceMode.PROXY。请注意,如果mode()设置为AdviceMode.ASPECTJ,则proxyTargetClass()属性的值将被忽略。还要注意,在这种情况下,spring-aspects模块JAR必须存在于类路径(classpath)中。

proxyTargetClass - 它定义了使用CGLIB或JDK的代理类型,默认为CGLIB。

使用@Async注释

此注释在方法级别上用于您希望它执行在单独线程中的那些方法。如果使用此注释标注公共方法,则此注释将按预期工作。

此外,该方法需要从不同的类中调用,以便它可以被代理,否则代理将被绕过。

以下是@Async注释方法的示例。它不会返回任何值。

@Override
@Async
public void createUserWithDefaultExecutor(){
	//SimpleAsyncTaskExecutor
	System.out.println("Currently Executing thread name - " + Thread.currentThread().getName());
	System.out.println("User created with default executor");
}
默认情况下,Spring将搜索关联的线程池定义:或者是上下文中唯一的TaskExecutor bean,或者是一个名为“taskExecutor”的Executor bean。如果两者都不可解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用

在方法返回类型中使用@Async注释

方法的实际返回类型可以包装在Future对象中。
 

@Override
@Async
public Future createAndReturnUser() {
	System.out.println("Currently Executing thread name - " + Thread.currentThread().getName());
	try {
		User user = new User();
		user.setFirstName("John");
		user.setLastName("Doe");
		user.setGender("Male");
		Thread.sleep(5000);
		return new AsyncResult(user);
	} catch (InterruptedException e) {
		System.out.println(e.getMessage());
	}
	return null;
}
以下是对此的测试方法。
@Test
public void createAndReturnUserTest() throws ExecutionException, InterruptedException {
	System.out.println("Current Thread in test class " + Thread.currentThread().getName());
	long startTime = System.currentTimeMillis();
	Future futureUser = userService.createAndReturnUser();
	futureUser.get();
	assertTrue((System.currentTimeMillis() - startTime) >= 5000);
}

在方法级定义ThreadPoolTask​​Executor和ConcurrentTaskExecutor

默认情况下,Spring使用SimpleAsyncTaskExecutor运行用@Async注释的方法。我们也可以按照以下方式定义我们的自定义执行程序bean并在方法级别使用它。

ThreadPoolTask​​Executor类
@Bean(name = "threadPoolExecutor")
public Executor getAsyncExecutor() {
	ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
	executor.setCorePoolSize(7);
	executor.setMaxPoolSize(42);
	executor.setQueueCapacity(11);
	executor.setThreadNamePrefix("threadPoolExecutor-");
	executor.initialize();
	return executor;
}
ConcurrentTaskExecutor
@Bean(name = "ConcurrentTaskExecutor")
public TaskExecutor taskExecutor2 () {
	return new ConcurrentTaskExecutor(
			Executors.newFixedThreadPool(3));
}
这些bean可以通过以下方式在方法级别使用
@Override
@Async("threadPoolExecutor")
public void createUserWithThreadPoolExecutor(){
	System.out.println("Currently Executing thread name - " + Thread.currentThread().getName());
	System.out.println("User created with thread pool executor");
}

@Override
@Async("ConcurrentTaskExecutor")
public void createUserWithConcurrentExecutor(){
	System.out.println("Currently Executing thread name - " + Thread.currentThread().getName());
	System.out.println("User created with concurrent task executor");
}

如果你想执行一些长时间执行的任务,例如,如果你想在一天结束时压缩日志文件,SimpleAsyncTaskExecutor在情况下是有意义的。在其他情况下,如果您想每隔n秒或几分钟执行一次执行短时执行的任务,则应该使用ThreadPoolTask​​Executor,因为重用了系统资源。

在应用程序级别实现执行程序

要在应用程序级别实现执行程序,我们需要实现AsyncConfigurer并覆盖folowing方法。
 

@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(7);
        executor.setMaxPoolSize(42);
        executor.setQueueCapacity(11);
        executor.setThreadNamePrefix("MyExecutor-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }
}

以下是异常处理程序。

AsyncExceptionHandler.class
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {

        System.out.println("Exception Cause - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }
}