欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring中@Async注解执行异步任务的方法

程序员文章站 2023-12-20 08:36:10
引言 在业务处理中,有些业务使用异步的方式更为合理。比如在某个业务逻辑中,把一些数据存入到redis缓存中,缓存只是一个辅助的功能,成功或者失败对主业务并不会产生根本...

引言

在业务处理中,有些业务使用异步的方式更为合理。比如在某个业务逻辑中,把一些数据存入到redis缓存中,缓存只是一个辅助的功能,成功或者失败对主业务并不会产生根本影响,这个过程可以通过异步的方法去进行。

spring中通过在方法上设置@async注解,可使得方法被异步调用。也就是说该方法会在调用时立即返回,而这个方法的实际执行交给spring的taskexecutor去完成。

代码示例

项目是一个普通的spring的项目,spring的配置文件:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:task="http://www.springframework.org/schema/task"
  xsi:schemalocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd
  http://www.springframework.org/schema/task
  http://www.springframework.org/schema/task/spring-task.xsd">

 <!-- 包扫描 -->
 <context:component-scan base-package="com.lzumetal.ssm"/>

 <!-- 执行异步任务的线程池taskexecutor -->
 <task:executor id="myexecutor" pool-size="5" />
 <task:annotation-driven executor="myexecutor"/>

</beans>

两个service类:

package com.lzumetal.ssm.anotation.service;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;

import java.util.concurrent.executionexception;
import java.util.concurrent.future;

/**
 * 业务service
 */
@service
public class businessservice {

 private static final logger log = loggerfactory.getlogger(businessservice.class);

 @autowired
 private cacheservice cacheservice;


 public void dobusiness() {
  log.error("start to deal with our business");
  cacheservice.cachedata();
  log.error("comlete service operation");
 }

 /**
  * 获取异步方法执行的返回值
  */
 public void dobusinesswithasyncreturn() throws executionexception, interruptedexception {
  log.error("start to deal with our business");
  future<string> future = cacheservice.cachedatawithreturn();
  log.error(future.get()); //future.get()方法是会阻塞的
  log.error("comlete service operation");
 }
}
package com.lzumetal.ssm.anotation.service;

import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.scheduling.annotation.async;
import org.springframework.scheduling.annotation.asyncresult;
import org.springframework.stereotype.service;

import java.util.concurrent.future;
import java.util.concurrent.timeunit;

/**
 * 缓存服务
 */
@service
public class cacheservice {

 private static final logger log = loggerfactory.getlogger(cacheservice.class);


 @async(value = "myexecutor") //指定执行任务的taskexecutor
 public void cachedata() {
  try {
   timeunit.seconds.sleep(3l);
  } catch (interruptedexception e) {
   e.printstacktrace();
  }
  log.error("success store the result to cache");
 }


 @async
 public future<string> cachedatawithreturn() {
  try {
   timeunit.seconds.sleep(3l);
  } catch (interruptedexception e) {
   e.printstacktrace();
  }
  log.error("success store the result to cache");
  //返回的结果需要通过asyncresult这个类包装
  return new asyncresult<>("async operation success");
 }
}

测试类:

package com.lzumetal.ssm.anotation.test;

import com.lzumetal.ssm.anotation.service.businessservice;
import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;

import java.util.concurrent.timeunit;

@runwith(springjunit4classrunner.class)
@contextconfiguration(locations = {"classpath:spring-context.xml"})
public class maintest {


 @autowired
 private businessservice businessservice;


 @test
 public void test() throws interruptedexception {
  businessservice.dobusiness();
  //不让主线程过早结束,否则控制台看不到异步方法中的输出内容
  timeunit.seconds.sleep(5l);  
 }

 @test
 public void testasyncreturn() throws exception {
  businessservice.dobusinesswithasyncreturn();
  timeunit.seconds.sleep(5l);
 }

}

执行test()方法的结果:

22:20:33,207  info main support.defaulttestcontextbootstrapper:260 - loaded default testexecutionlistener class names from location [meta-inf/spring.factories]: [org.springframework.test.context.web.servlettestexecutionlistener, org.springframework.test.context.support.dirtiescontextbeforemodestestexecutionlistener, org.springframework.test.context.support.dependencyinjectiontestexecutionlistener, org.springframework.test.context.support.dirtiescontexttestexecutionlistener, org.springframework.test.context.transaction.transactionaltestexecutionlistener, org.springframework.test.context.jdbc.sqlscriptstestexecutionlistener]
22:20:33,226  info main support.defaulttestcontextbootstrapper:209 - could not instantiate testexecutionlistener [org.springframework.test.context.web.servlettestexecutionlistener]. specify custom listener classes or make the default listener classes (and their required dependencies) available. offending class: [javax/servlet/servletcontext]
22:20:33,227  info main support.defaulttestcontextbootstrapper:187 - using testexecutionlisteners: [org.springframework.test.context.support.dirtiescontextbeforemodestestexecutionlistener@100fc185, org.springframework.test.context.support.dependencyinjectiontestexecutionlistener@643b1d11, org.springframework.test.context.support.dirtiescontexttestexecutionlistener@2ef5e5e3, org.springframework.test.context.transaction.transactionaltestexecutionlistener@36d4b5c, org.springframework.test.context.jdbc.sqlscriptstestexecutionlistener@6d00a15d]22:20:33,324  info main xml.xmlbeandefinitionreader:317 - loading xml bean definitions from class path resource [spring-context.xml]
22:20:33,585  info main support.genericapplicationcontext:583 - refreshing org.springframework.context.support.genericapplicationcontext@4f7d0008: startup date [wed may 30 22:20:33 cst 2018]; root of context hierarchy
22:20:33,763  info main concurrent.threadpooltaskexecutor:165 - initializing executorservice
22:20:33,766  info main support.postprocessorregistrationdelegate$beanpostprocessorchecker:325 - bean 'myexecutor' of type [org.springframework.scheduling.config.taskexecutorfactorybean] is not eligible for getting processed by all beanpostprocessors (for example: not eligible for auto-proxying)
22:20:33,767  info main support.postprocessorregistrationdelegate$beanpostprocessorchecker:325 - bean 'myexecutor' of type [org.springframework.scheduling.concurrent.threadpooltaskexecutor] is not eligible for getting processed by all beanpostprocessors (for example: not eligible for auto-proxying)
22:20:34,107 error main service.businessservice:24 - start to deal with our business
22:20:34,113 error main service.businessservice:26 - comlete service operation
22:20:37,166 error myexecutor-1 service.cacheservice:28 - success store the result to cache
22:20:39,117  info thread-0 support.genericapplicationcontext:984 - closing org.springframework.context.support.genericapplicationcontext@4f7d0008: startup date [wed may 30 22:20:33 cst 2018]; root of context hierarchy
22:20:39,118  info thread-0 concurrent.threadpooltaskexecutor:203 - shutting down executorservice

执行testasyncreturn()方法的结果:

21:38:16,908  info main support.defaulttestcontextbootstrapper:260 - loaded default testexecutionlistener class names from location [meta-inf/spring.factories]: [org.springframework.test.context.web.servlettestexecutionlistener, org.springframework.test.context.support.dirtiescontextbeforemodestestexecutionlistener, org.springframework.test.context.support.dependencyinjectiontestexecutionlistener, org.springframework.test.context.support.dirtiescontexttestexecutionlistener, org.springframework.test.context.transaction.transactionaltestexecutionlistener, org.springframework.test.context.jdbc.sqlscriptstestexecutionlistener]
21:38:16,926  info main support.defaulttestcontextbootstrapper:209 - could not instantiate testexecutionlistener [org.springframework.test.context.web.servlettestexecutionlistener]. specify custom listener classes or make the default listener classes (and their required dependencies) available. offending class: [javax/servlet/servletcontext]
21:38:16,927  info main support.defaulttestcontextbootstrapper:187 - using testexecutionlisteners: [org.springframework.test.context.support.dirtiescontextbeforemodestestexecutionlistener@100fc185, org.springframework.test.context.support.dependencyinjectiontestexecutionlistener@643b1d11, org.springframework.test.context.support.dirtiescontexttestexecutionlistener@2ef5e5e3, org.springframework.test.context.transaction.transactionaltestexecutionlistener@36d4b5c, org.springframework.test.context.jdbc.sqlscriptstestexecutionlistener@6d00a15d]21:38:17,025  info main xml.xmlbeandefinitionreader:317 - loading xml bean definitions from class path resource [spring-context.xml]
21:38:17,263  info main support.genericapplicationcontext:583 - refreshing org.springframework.context.support.genericapplicationcontext@4f7d0008: startup date [wed may 30 21:38:17 cst 2018]; root of context hierarchy
21:38:17,405  info main concurrent.threadpooltaskexecutor:165 - initializing executorservice
21:38:17,407  info main support.postprocessorregistrationdelegate$beanpostprocessorchecker:325 - bean 'myexecutor' of type [org.springframework.scheduling.config.taskexecutorfactorybean] is not eligible for getting processed by all beanpostprocessors (for example: not eligible for auto-proxying)
21:38:17,407  info main support.postprocessorregistrationdelegate$beanpostprocessorchecker:325 - bean 'myexecutor' of type [org.springframework.scheduling.concurrent.threadpooltaskexecutor] is not eligible for getting processed by all beanpostprocessors (for example: not eligible for auto-proxying)
21:38:17,692 error main service.businessservice:35 - start to deal with our business
21:38:20,833 error myexecutor-1 service.cacheservice:39 - success store the result to cache
21:38:20,834 error main service.businessservice:37 - async operation success
21:38:20,835 error main service.businessservice:38 - comlete service operation
21:38:25,838  info thread-0 support.genericapplicationcontext:984 - closing org.springframework.context.support.genericapplicationcontext@4f7d0008: startup date [wed may 30 21:38:17 cst 2018]; root of context hierarchy
21:38:25,839  info thread-0 concurrent.threadpooltaskexecutor:203 - shutting down executorservice

@async的使用注意点

  1. 返回值:不要返回值直接void;需要返回值用asyncresult或者completablefuture
  2. 可自定义执行器并指定例如:@async("otherexecutor")
  3. @async必须不同类间调用: a类—>b类.c方法()(@async注释在b类/方法中),如果在同一个类中调用,会变同步执行,例如:a类.b()—>a类.@async c()。
  4. @async也可以加到类,表示这个类的所有方法都是异步执行,并且方法上的注解会覆盖类上的注解。但一般不这么用!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

上一篇:

下一篇: