诚信宁津建设网站免费网站制作在线

当前位置: 首页 > news >正文

诚信宁津建设网站,免费网站制作在线,中山网站建设方案托管,深圳 网站建设培训文章目录1、SpringBoot异步任务1.1使用注解EnableAsync开启异步任务支持1.2使用Async注解标记要进行异步执行的方法1.3controller测试2.异步任务相关限制3.1自定义 Executor3.1.1应用层级#xff1a;3.1.2方法层级#xff1a;3.2自定义 Executor (第二种方式)4.1异常处理4.1.… 文章目录1、SpringBoot异步任务1.1使用注解EnableAsync开启异步任务支持1.2使用Async注解标记要进行异步执行的方法1.3controller测试2.异步任务相关限制3.1自定义 Executor3.1.1应用层级3.1.2方法层级3.2自定义 Executor (第二种方式)4.1异常处理4.1.1自定义一个异常处理器类实现接口如下所示4.1.2创建一个自定义Executor异步配置类将我们的自定义异常处理器设置到其接口上4.1.3测试4.2异常处理第二种方式在SpringBoot应用程序中有时需要执行一些长时间运行的操作如发送电子邮件或从外部API获取数据。 这些操作可能需要几秒钟或几分钟才能完成。 如果您在主线程上执行此类操作则应用程序停止响应可能会导致用户体验不佳。 为了避免这种情况并使应用程序在执行此类操作时继续响应我们可以使用SpringBoot的异步任务功能。 异步任务是指可以在后台线程上执行的任务因此不会阻塞主线程。 有时候前端可能提交了一个耗时任务如果后端接收到请求后直接执行该耗时任务那么前端需要等待很久一段时间才能接受到响应。如果该耗时任务是通过浏览器直接进行请求那么浏览器页面会一直处于转圈等待状态。 事实上当后端要处理一个耗时任务时通常都会将耗时任务提交到一个异步任务中进行执行此时前端提交耗时任务后就可直接返回进行其他操作。 1、SpringBoot异步任务 SpringBoot开启异步任务的步骤如下 在SpringBootApplication类上添加EnableAsync注解启用SpringBoot异步任务支持。在异步方法所在的类上添加Async注解标记该类中需要异步执行的方法。在异步方法中使用CompletableFuture等类处理异步操作。 使用SpringBoot异步任务功能可以轻松地将长时间运行的操作转换为异步任务提高应用程序的响应性能和用户体验。 1.1使用注解EnableAsync开启异步任务支持 SpringBootApplication EnableAsync public class ApplicationStarter {public static void main(String[] args) {SpringApplication.run(ApplicationStarter.class,args);} }1.2使用Async注解标记要进行异步执行的方法 Service public class AsyncService {Asyncpublic void t1() throws InterruptedException {// 模拟耗时任务Thread.sleep(TimeUnit.SECONDS.toMillis(5));}Asyncpublic FutureString t2() throws InterruptedException {// 模拟耗时任务Thread.sleep(TimeUnit.SECONDS.toMillis(5));return new AsyncResult(async tasks done!);} }1.3controller测试 Autowiredprivate AsyncService asyncService;GetMapping(/task1)public String asyncTaskWithoutReturnType() throws InterruptedException {asyncService.t1();return rrrr;}GetMapping(/task2)public String asyncTaskWithReturnType() throws InterruptedException, ExecutionException {asyncService.t2();return aaaaaaa;}被Async注解的方法可以接受任意类型参数但只能返回void或Future类型数据 所以当异步方法返回数据时需要使用Future包装异步任务结果上述代码使用AsyncResult包装异步任务结果AsyncResult间接继承Future是 Spring 提供的一个可用于追踪异步方法执行结果的包装类。其他常用的Future类型还有 Spring 4.2 提供的ListenableFuture或者 JDK 8 提供的CompletableFuture这些类型可提供更丰富的异步任务操作。 如果前端需要获取耗时任务结果则异步任务方法应当返回一个Future类型数据此时Controller相关接口需要调用该Future的get()方法获取异步任务结果get()方法是一个阻塞方法因此该操作相当于将异步任务转换为同步任务浏览器同样会面临我们前面所讲的转圈等待过程但是异步执行还是有他的好处的因为我们可以控制get()方法的调用时序因此可以先执行其他一些操作后最后再调用get()方法。 2.异步任务相关限制 被Async注解的异步任务方法存在相关限制 被Async注解的方法必须是public的这样方法才可以被代理。不能在同一个类中调用Async方法因为同一个类中调用会绕过方法代理调用的是实际的方法。被Async注解的方法不能是static。Async注解不能与 Bean 对象的生命周期回调函数比如PostConstruct一起注解到同一个方法中。异步类必须注入到 Spring IOC 容器中也即异步类必须被Component/Service等进行注解。其他类中使用异步类对象必须通过Autowired等方式进行注入不能手动new对象。 SpringBoot异步任务功能虽然可以提高应用程序的响应性能但还是有一些限制需要注意 异步方法不能与同步方法在同一个类中定义。必须将异步方法定义在单独的类中或者使用CGLIB代理来将异步方法包装在另一个类中。异步方法不能是private或final的。异步方法不能返回void类型。必须返回一个Future或CompletableFuture对象以便在异步任务完成后处理结果。如果异步方法在同一类中调用另一个异步方法则调用将不会异步执行而是在同一线程中同步执行。 总之虽然SpringBoot的异步任务功能可以提高应用程序的响应性能但在使用时需要注意这些限制以确保异步方法能够正确地执行并保持应用程序的稳定性。 3.1自定义 Executor 默认情况下Spring 会自动搜索相关线程池定义要么是一个唯一TaskExecutor Bean 实例要么是一个名称为taskExecutor的Executor Bean 实例。如果这两个 Bean 实例都不存在就会使用SimpleAsyncTaskExecutor来异步执行被Async注解的方法。 综上可以知道默认情况下Spring 使用的 Executor 是SimpleAsyncTaskExecutorSimpleAsyncTaskExecutor每次调用都会创建一个新的线程不会重用之前的线程。很多时候这种实现方式不符合我们的业务场景因此通常我们都会自定义一个 Executor 来替换SimpleAsyncTaskExecutor。 对于自定义 Executor自定义线程池可以分为如下两个层级 应用层级即全局生效的 Executor。依据 Spring 默认搜索机制其实就是配置一个全局唯一的TaskExecutor实例或者一个名称为taskExecutor的Executor实例即可如下所示方法层级即为单独一个或多个方法指定运行线程池其他未指定的异步方法运行在默认线程池。如下所示 3.1.1应用层级 下面代码定义了一个名称为taskExecutor的Executor此时Async方法默认就会运行在该Executor中。 Configuration public class ExcuterConfig {Bean(taskExecutor)public Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();// 设置核心线程数int cores Runtime.getRuntime().availableProcessors();executor.setCorePoolSize(cores);// 设置最大线程数executor.setMaxPoolSize(20);// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);// 设置线程默认前缀名executor.setThreadNamePrefix(Application-Level-Async-);return executor;} }3.1.2方法层级 package com.buba.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;Configuration public class ExcuterConfig {Bean(methodLevelExecutor1)public TaskExecutor getAsyncExecutor1() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(4);// 设置最大线程数executor.setMaxPoolSize(20);// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);// 设置线程默认前缀名executor.setThreadNamePrefix(Method-Level-Async1-);return executor;}Bean(methodLevelExecutor2)public TaskExecutor getAsyncExecutor2() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(8);// 设置最大线程数executor.setMaxPoolSize(20);// 等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);// 设置线程默认前缀名executor.setThreadNamePrefix(Method-Level-Async2-);return executor;} }上述特意设置了多个TaskExecutor因为如果只设置一个TaskExecutor那么 Spring 就会默认采用该TaskExecutor作为所有Async的Executor而设置了多个TaskExecutorSpring 检测到全局存在多个Executor就会降级使用默认的SimpleAsyncTaskExecutor此时我们就可以为Async方法配置执行线程池其他未配置的Async就会默认运行在SimpleAsyncTaskExecutor中这就是方法层级的自定义 Executor。如下代码所示 Service public class AsyncService {Async(methodLevelExecutor1)public void t1() throws InterruptedException {// 模拟耗时任务Thread.sleep(TimeUnit.SECONDS.toMillis(5));}Async(methodLevelExecutor2)public FutureString t2() throws InterruptedException {// 模拟耗时任务Thread.sleep(TimeUnit.SECONDS.toMillis(5));return new AsyncResult(async tasks done!);} }3.2自定义 Executor (第二种方式) Spring Boot提供了默认的任务执行器但是有时候我们需要自定义任务执行器以更好地控制任务执行的线程池。在Spring Boot中我们可以通过实现AsyncConfigurer接口来自定义任务执行器。下面是一个使用自定义任务执行器的示例 Configuration EnableAsync public class AppConfig implements AsyncConfigurer {Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(100);executor.setQueueCapacity(500);executor.setThreadNamePrefix(MyExecutor-);executor.initialize();return executor;} }在上面的示例中我们实现了AsyncConfigurer接口并覆盖了getAsyncExecutor()方法。在该方法中我们创建了一个ThreadPoolTaskExecutor对象并设置了线程池的核心线程数、最大线程数、队列容量和线程名称前缀。最后我们返回这个线程池对象。 通过实现AsyncConfigurer接口并覆盖getAsyncExecutor()方法我们可以轻松地自定义任务执行器。在应用程序中使用自定义任务执行器时只需将其添加到异步方法所在的类上即可。例如 Service public class MyService {Async(myExecutor)public CompletableFutureString longRunningMethod() {// long running code here} }在上面的示例中我们将Async注解的value属性设置为myExecutor这是我们在AppConfig类中定义的自定义任务执行器的名称。 总之通过自定义任务执行器我们可以更好地控制异步任务的执行从而提高应用程序的性能和可靠性。 4.1异常处理 前文介绍过对于被Async注解的异步方法只能返回void或者Future类型。对于返回Future类型数据如果异步任务方法抛出异常则很容易进行处理因为Future.get()会重新抛出该异常我们只需对其进行捕获即可。但是对于返回void的异步任务方法异常不会传播到被调用者线程因此我们需要自定义一个额外的异步任务异常处理器捕获异步任务方法抛出的异常。 4.1.1自定义一个异常处理器类实现接口如下所示 public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {Overridepublic void handleUncaughtException(Throwable throwable, Method method, Object… objects) {System.out.println(Exception message - throwable.getMessage());System.out.println(Method name - method.getName());for (Object param : objects) {System.out.println(Parameter value - param);}} }4.1.2创建一个自定义Executor异步配置类将我们的自定义异常处理器设置到其接口上 Configuration EnableAsync public class AsyncConfigure implements AsyncConfigurer {Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new CustomAsyncExceptionHandler();} }此时异步方法如果抛出异常就可以被我们的自定义异步异常处理器捕获得到。 4.1.3测试 Service public class AsyncService {Async(methodLevelExecutor1)public void t1() throws InterruptedException {// 模拟耗时任务Thread.sleep(TimeUnit.SECONDS.toMillis(5));throw new NullPointerException();}4.2异常处理第二种方式 SpringBoot异步任务的异常可以通过Async注解的exceptional属性捕获。将exceptional属性设置为要捕获的异常类型即可。例如以下示例演示如何捕获RuntimeException Async(exceptional RuntimeException.class) public CompletableFutureString sendEmail() {// send email code here that may throw a RuntimeException }在上面的示例中如果sendEmail()方法抛出RuntimeException则该异常将被捕获并包装在CompletableFuture对象中返回。 另一种捕获异步任务异常的方法是使用Async注解的异步方法的返回类型。如果异步方法的返回类型是CompletableFuture则可以使用CompletableFuture的exceptionally()方法捕获异步任务的异常。例如以下示例演示如何使用CompletableFuture的exceptionally()方法捕获异步任务的异常 Async public CompletableFutureString sendEmail() {// send email code here that may throw a RuntimeException }CompletableFutureString future sendEmail(); future.exceptionally(ex - {// handle the exception herereturn Error sending email: ex.getMessage(); });在上面的示例中如果sendEmail()方法抛出RuntimeException则可以在future.exceptionally()方法中捕获该异常并处理它。注意exceptionally()方法返回一个新的CompletableFuture对象该对象包含捕获到的异常或原始异步操作的结果。 总之SpringBoot提供了多种捕获异步任务异常的方法包括使用Async注解的exceptional属性和CompletableFuture对象的exceptionally()方法。这些方法可以帮助我们更好地管理和处理异步任务的异常提高应用程序的可靠性和稳定性。