spring异步机制

近期在组内做了一次spring的异步分享,将内容记录下来。

转载请注明出处:https://blog.csdn.net/dhtx_wzgl/article/details/85229397

0、概念

同步、异步和阻塞、非阻塞

1、spring异步实现

2、spring阻塞异步的使用

环境最低要求:spring3.2+(3.0开始支持服务层异步,3.2开始支持控制层异步)、servlet3.0+、tomcat7.0+、java6+

本文demo环境:spring5、servlet3.1、tomcat8、java8

建议环境:spring5、servlet3.1、tomcat8.5、java8

2.1 服务层异步

2.1.1 使用

1)、启动类或者配置类上加@EnableAsync,或者直接通过xml配置

配置类方法

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

xml配置方法

<!--开启注解调度支持 @Async-->
<task:annotation-driven executor="executor" proxy-target-class="true"/>
<!-- 任务执行器 -->
<task:executor id="executor" pool-size="1-10" keep-alive="1000" queue-capacity="10" rejection-policy="CALLER_RUNS"/>

参数解析:

<task:annotation-driven/>

executor指定一个缺省的executor给@Async使用

proxy-target-class:是否使用基于类的代理,默认为false

<task:executor/>

参数名 类型 是否必填 描述
id string 必填 线程池实例名,唯一标识
pool-size string 可选

值既可以是单值也可以是一个范围(m-n),如果任务队列无界,那么n无效,但是m=0时除外,此时,coresize=n,allowCoreThreadTimeout=true;当队列有界时,coresize=m,maxsize=n;默认值为coresize=1,maxsize=Integer.MAX_VALUE;当为单值时(pool-size="n"),coresize=n,maxsize=Integer.MAX_VALUE。

queue-capacity

string 可选 任务队列,默认值为Integer.MAX_VALUE,即无界
keep-alive string 可选 线程超时时间
rejection-policy string 可选 任务 拒绝策略:
  • ABORT(缺省):抛出TaskRejectedException异常,然后不执行
  • DISCARD:不执行,也不抛出异常
  • DISCARD_OLDEST:丢弃queue中最旧的那个任务
  • CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

2)、在被调用的方法或所属类上加上@Async注解

//类声明上加注解
@Service
@Slf4j
@Async
public class AsyncService {
 
//方法声明上加注解
@Async
public void say(String var) throws InterruptedException {

3)、

a、调用方法和被调用方法必须在不同的类中,因为调用同一个类中的方法时,被调用方法上的注解都会失效。

b、@Async与@Transactional同时使用时,事物不起作用。

2.1.2 demo

@Slf4j
public class SleepUtil {
    private static Random random = new Random();
 
    public static void sleep() throws InterruptedException {
        int timeOut = random.nextInt(3000);
        log.info("休眠时间:{}ms",timeOut);
        Thread.sleep(timeOut);
    }
}

@Service
@Slf4j
@Async
public class AsyncService {
    /**
     * 无返回值
     *
     * @param var
     * @throws InterruptedException
     */
    public void say(String var) throws InterruptedException {
        log.info("开始执行无返回值阻塞异步方法");
        Stopwatch stopwatch = Stopwatch.createStarted();
        sleep();
        log.info("say:{}", var);
        log.info("完成无返回值阻塞异步方法执行,参数:{},耗时:{}", var, stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }
 
    /**
     * 普通返回值
     *
     * @param var
     * @return
     * @throws InterruptedException
     */
    public String sayHasRetrun(String var) throws InterruptedException {
        log.info("开始执行普通返回值阻塞异步方法");
        Stopwatch stopwatch = Stopwatch.createStarted();
        sleep();
        log.info("say:{}", var);
        log.info("完成普通返回值阻塞异步方法执行,参数:{},耗时:{}", var, stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return "看到结果没?";
    }
 
    /**
     * future返回值
     *
     * @param var
     * @return
     * @throws InterruptedException
     */
    public Future<String> sayForFuther(String var) throws InterruptedException {
        log.info("开始执行回调返回值阻塞异步方法");
        Stopwatch stopwatch = Stopwatch.createStarted();
        sleep();
        log.info("say:{}", var);
        log.info("完成回调返回值阻塞异步方法执行,参数:{},耗时:{}", var, stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return new AsyncResult<>("FutureResult:" + var);
    }
}

public class AysncServiceTest extends BaseTest {
    @Resource
    private AsyncService aysncService;

    @Test
    public void say() throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        aysncService.say("hello");
        LOGGER.info("result:用时:{}ms",stopwatch.elapsed(TimeUnit.MILLISECONDS));
    }

    @Test
    public void sayHasRetrun() throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        String result = aysncService.sayHasRetrun("hello");
        LOGGER.info("result:{},用时:{}ms",result,stopwatch.elapsed(TimeUnit.MILLISECONDS));
        Thread.sleep(1000);
    }

    @Test
    public void sayForFuther() throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        Future<String> future = aysncService.sayForFuther("hello");
        LOGGER.info("result:{},用时:{}ms",stopwatch.elapsed(TimeUnit.MILLISECONDS),future.get());
        Thread.sleep(1000);
    }
}

2.2 控制层异步

2.2.1 使用

1)、在web.xml中的所有servlet和filter声明中添加<async-supported>true</async-supported>,例如

<filter>
    <filter-name>watcher</filter-name>
    <filter-class>qunar.ServletWatcher</filter-class>
    <async-supported>true</async-supported>
</filter>
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

2)、<async-supported>true</async-supported>只在3.0版本以上的xml配置文件,所以需要将低版本的web.xml文件头改为3.0或以上版本

<web-app version="3.0"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" >

3)、controller接口返回值必须是回调接口,比如Callable、DeferredResult等。

2.2.2 demo

@RestController
@Slf4j
public class DemoController {
   @Resource
   private NormalService normalService;
 
    @GetMapping("/async")
    public Callable<String> async(final String var) throws InterruptedException, ExecutionException {
        Stopwatch stopwatch = Stopwatch.createStarted();
       Callable<String> callable = new Callable<String>() {
           @Override
           public String call() throws Exception {
               return "hello "+var;
           }
       };
        log.info("async used time {} ms",stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return callable;
    }
    @GetMapping("/sync")
    public String get(String var) throws InterruptedException, ExecutionException {
         Stopwatch stopwatch = Stopwatch.createStarted();
          String result = normalService.sayHasRetrun(var);
         log.info("sync used time {} ms",stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return result;
    }
}
 
 
@Service
@Slf4j
public class NormalService {
    public String sayHasRetrun(String var) throws InterruptedException {
        log.info("开始执行普通返回值阻塞方法");
        Stopwatch stopwatch =Stopwatch.createStarted();
        sleep();
        log.info("say:{}",var);
        log.info("完成普通返回值阻塞方法执行,参数:{},耗时:{}",var,stopwatch.elapsed(TimeUnit.MILLISECONDS));
        return "看到结果没?";
    }
}


@Slf4j
public class DemoControllerTest extends MockTest {

    @Test
    public void async() throws Exception {
        MvcResult mvcResult = mockMvc.perform(
                get("/async2")
                        .param("var", "async"))
                .andReturn();
//        LOGGER.info("返回结果:{}", mvcResult.getResponse().getContentAsString());
        LOGGER.info("返回结果:{}", mvcResult.getAsyncResult(3000));
    }
    @Test
    public void sync() throws Exception {
        MvcResult mvcResult = mockMvc.perform(
                get("/sync")
                        .param("var", "sync"))
                .andReturn();
        LOGGER.info("返回结果:{}", mvcResult.getResponse().getContentAsString());
    }
}

3、扩展阅读

spring webflux 学习

spring webflux: http://www.liuhaihua.cn/archives/512708.html

异步非异步:https://juejin.im/post/5b4cd263e51d4519846971e0

servlet: https://www.jianshu.com/p/c23ca9d26f64 

reactor: https://www.ibm.com/developerworks/cn/java/j-cn-with-reactor-response-encode/index.html

spring5异步:http://www.infoq.com/cn/articles/Servlet-and-Reactive-Stacks-Spring-Framework-5

spring@Async:https://blog.csdn.net/ClementAD/article/details/47403185 

spring@Async执行源码:https://www.jianshu.com/p/6a3c335b8839

srping控制层异步: https://yq.aliyun.com/articles/622413?utm_content=m_1000011297

spring控制层异步源码分析:https://blog.csdn.net/woshilijiuyi/article/details/79316105

DeferredResult: https://www.jianshu.com/p/acd4bbd83314

Callable vs DeferredResult :https://www.cnblogs.com/aheizi/p/5659030.html

CGLIB :https://blog.csdn.net/zghwaicsdn/article/details/50957474

tomcat:

http://www.cnblogs.com/kismetv/p/7228274.html
https://www.cnblogs.com/kismetv/p/7806063.html

猜你喜欢

转载自blog.csdn.net/dhtx_wzgl/article/details/85229397