首页 > 其他分享 >spring - mvc - @Async

spring - mvc - @Async

时间:2024-03-08 10:36:54浏览次数:16  
标签:异步 spring System mvc println Async public out

@Async
@EnableAsync

1.启用异步支持

@EnableAsync注释在我们的应用程序中启用异步处理。具有类似功能的 XML 等效项是使用executor属性的task:*命名空间。

让我们首先通过Java 配置启用异步处理。
我们将通过将@EnableAsync添加到配置类来完成此操作:

@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }

启用注释就足够了。但也有一些简单的配置选项:
注解–默认情况下, @EnableAsync检测 Spring 的@Async注解和 EJB 3.1 javax.ejb.Asynchronous。我们也可以使用此选项来检测其他用户定义的注释类型。
mode 指示应使用的建议类型
proxyTargetClass指示应使用的代理类型仅当模式设置为AdviceMode.PROXY时,此属性才有效。
order设置应用AsyncAnnotationBeanPostProcessor的顺序默认情况下,它最后运行,以便它可以考虑所有现有代理。
我们还可以使用任务命名空间通过XML 配置启用异步处理:

<task:executor id="myexecutor" pool-size="5"  />
<task:annotation-driven executor="myexecutor"/>

2.@Async注解

首先,让我们回顾一下规则。@Async有两个限制:
它必须仅应用于公共方法。
自调用(从同一个类中调用异步方法)将不起作用。
原因很简单:该方法需要公开 ,以便可以被代理。并且自调用不起作用,因为它绕过代理并直接调用底层方法。
这是配置具有 void 返回类型的方法以异步运行的简单方法:

@Async
public void asyncMethodWithVoidReturnType() {
    System.out.println("Execute method asynchronously. " 
      + Thread.currentThread().getName());
}

我们还可以 通过将实际返回包装在 Future 中来将@Async应用于具有返回类型的方法:

@Async
public Future<String> asyncMethodWithReturnType() {
    System.out.println("Execute method asynchronously - " 
      + Thread.currentThread().getName());
    try {
        Thread.sleep(5000);
        return new AsyncResult<String>("hello world !!!!");
    } catch (InterruptedException e) {
        //
    }

    return null;
}

Spring 还提供了一个实现Future 的AsyncResult类。我们可以用它来跟踪异步方法执行的结果。
现在让我们调用上述方法并使用Future对象检索异步过程的结果。

public void testAsyncAnnotationForMethodsWithReturnType()
  throws InterruptedException, ExecutionException {
    System.out.println("Invoking an asynchronous method. " 
      + Thread.currentThread().getName());
    Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();

    while (true) {
        if (future.isDone()) {
            System.out.println("Result from asynchronous process - " + future.get());
            break;
        }
        System.out.println("Continue doing something else. ");
        Thread.sleep(1000);
    }
}

3.执行器

默认情况下,Spring 使用SimpleAsyncTaskExecutor来实际异步运行这些方法。但我们可以在两个级别覆盖默认值:应用程序级别或单个方法级别。

4.在方法级别重写执行器

我们需要在配置类中声明所需的执行器:

@Configuration
@EnableAsync
public class SpringAsyncConfig {
    
    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        return new ThreadPoolTaskExecutor();
    }
}

然后我们应该在@Async中提供执行程序名称作为属性:

@Async("threadPoolTaskExecutor")
public void asyncMethodWithConfiguredExecutor() {
    System.out.println("Execute method with configured executor - "
      + Thread.currentThread().getName());
}

5.在应用程序级别覆盖执行器

配置类应实现AsyncConfigurer接口。因此,它必须实现getAsyncExecutor()方法。在这里,我们将返回整个应用程序的执行器。现在,这成为运行用@Async注释的方法的默认执行器:

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {
   @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}

6.异常处理

当方法返回类型是Future时,异常处理很容易。Future.get()方法将抛出异常。
但如果返回类型为void,异常将不会传播到调用线程。因此,我们需要添加额外的配置来处理异常。
我们将通过实现AsyncUncaughtExceptionHandler接口来创建自定义异步异常处理程序。当存在任何未捕获的异步异常时,将调用handleUncaughtException ()方法:

public class CustomAsyncExceptionHandler
  implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(
      Throwable throwable, Method method, Object... obj) {
 
        System.out.println("Exception message - " + throwable.getMessage());
        System.out.println("Method name - " + method.getName());
        for (Object param : obj) {
            System.out.println("Parameter value - " + param);
        }
    }
    
}

在上一节中,我们了解了配置类实现的AsyncConfigurer接口。作为其中的一部分,我们还需要重写getAsyncUncaughtExceptionHandler()方法以返回我们的自定义异步异常处理程序:

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

标签:异步,spring,System,mvc,println,Async,public,out
From: https://www.cnblogs.com/dkpp/p/18060416

相关文章

  • 当未指定且存在多个构造器,实例化对象时Spring如何选择?
    前言在前面的讲解中,我们了解了如何获取构造器。当只有一个符合条件的构造器时,自然会选择它作为初始化的构造器。然而,在上一节中,我们遇到了一种特殊情况:当有多个符合条件的构造器时,返回的是一个数组。在这种情况下,Spring又是如何从多个构造器中选择最合适的呢?今天,我们将讨论的主题......
  • spring - mvc - @Scheduled
    @Scheduled1.启用调度支持为了在Spring中启用对调度任务和@Scheduled注释的支持,我们可以使用Java启用样式注释:@Configuration@EnableSchedulingpublicclassSpringConfig{...}相反,我们可以在XML中做同样的事情:<task:annotation-driven>2.按固定延迟安排任务......
  • spring - springmvc - @EnableCaching
    @EnableCaching@EnableCaching注释在应用程序中启用注释驱动的缓存管理功能,并允许我们在应用程序中使用@Cacheable和@CacheEvict注释。具有类似功能的XML等效项是cache:*命名空间:@Configuration@EnableCachingpublicclassCacheConfig{@BeanpublicCacheMana......
  • SpringBoot 支付宝付款接口类、支付异步回调函数模板
    1.付款接口类1.1.引入Maven依赖<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.38.221.ALL</version></dependency>1.2.将下面代码保存为AlipayTemplate.java@Config......
  • SpringBoot-重要注解(1)
    ConfigurationProperties注解https://blog.csdn.net/skh2015java/article/details/120141409@Import、@ImportAutoConfigurationhttps://www.cnblogs.com/imyjy/p/16092825.html当我们需要在一个配置类中导入另一个Configuration配置类时,可以使用@Import、@ImportAuto......
  • Spring框架Bean对象的五个作用域
    ​ 一、前言:Bean对象简介在Spring项目中,那些由Spring IoC容器所管理的对象,称为bean。简单地讲,bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。 而bean定义以及bean相互间的依赖关系将通过配置元数据来描述。上一段描述......
  • spring - mvc
    springmvc1.@Autowired@ComponentpublicclassFooService{@AutowiredprivateFooFormatterfooFormatter;}2.通过@Qualifier自动装配例如,让我们看看如何使用@Qualifier注释来指示所需的bean。首先,我们将定义2个Formatter类型的bean:@Component("fooFo......
  • SpringBoot3+Consul配置,启动后,居然不读bootstrap.yml的配置文件,直接连本地localhost:8
    问题描述如题。bootstrap.yml的配置文件: consul控制台打印的日志: 解决方案:booststrap.yml的配置文件缩进搞错了,所以压根就没有读到配置。正确的缩进:  ......
  • spring-webClient-响应式http客户端
    1.WebClient简介WebClient是SpringWebFlux模块提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。WebFlux对标SpringMvc,WebClient相当于RestTemplate,同时也是Spring官方的Http请求工具。2.传统阻塞IO模型VS响应式IO模型传统阻塞IO模型RestTem......
  • spring-restTemplate-网络请求
    1,引言  现如今的IT项目,由服务端向外发起网络请求的场景,基本上处处可见!传统情况下,在服务端代码里访问http服务时,一般会使用JDK的HttpURLConnection或者Apache的HttpClient,不过这种方法使用起来太过繁琐,而且api使用起来非常的复杂,还得操心资源回收。  RestTempl......