• 前言
    最近在做一个用户反馈的功能,就是当用户反馈意见或建议后服务端将意见保存然后发邮件给相关模块的开发者。考虑发邮件耗时的情况所以我想用异步的方法去执行,于是就开始研究Spring的@Async了。但网上的许多教程都是相互抄袭且直接复制代码的,根本没有去自己实践或者更改代码,所以在这两天我遇到了许多问题,使得@Async无效,也一直没有找到很好的文章去详细的说明@Async的正确及错误的使用方法及需要注意的地方,这里Sring是以配置文件的形式来开启@Async,而SpringBoot则是以注解的方式开启。
  • 教程
  1. Spring配置文件
    配置文件的话有两种方式一种是精简式:
    直接在applicationContext.xml中加入开启异步并添加task的命名空间

    <task:executor id="WhifExecutor" pool-size="10"/>
    <task:annotation-driven executor="WhifExecutor" />
    xmlns:task="http://www.springframework.org/schema/task"
    http://www.springframework.org/schema/task
    http://www.springframework.org/schema/task/spring-task.xsd

    这样好处是简单快速,缺点是线程池配置简单,线程创建不能定时关闭。
    所以我推荐下面这种,定义一个线程池,然后引入。其实两种方法原理是一样只不过下面这种只是线程池配置更加详细,线程在空闲后会根据存活时间配置进行关闭。
    在applicationContext.xml同目录下创建文件threadPool.xml内容如下,然后在applicationContext.xml中引入threadPool.xml:<import resource="threadPool.xml" />

    <?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:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"><!-- 开启异步,并引入线程池 --><task:annotation-driven executor="threadPool" /><!-- 定义线程池 --><bean id="threadPool"class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"><!-- 核心线程数,默认为1 --><property name="corePoolSize" value="5" /><!-- 最大线程数,默认为Integer.MAX_VALUE --><property name="maxPoolSize" value="20" /><!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE --><property name="queueCapacity" value="500" /><!-- 线程池维护线程所允许的空闲时间,默认为60s --><property name="keepAliveSeconds" value="30" /><!-- 完成任务自动关闭 , 默认为false--><property name="waitForTasksToCompleteOnShutdown" value="true" /><!-- 核心线程超时退出,默认为false --><property name="allowCoreThreadTimeOut" value="true" /><!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 --><property name="rejectedExecutionHandler"><!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 --><!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 --><!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 --><!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 --><bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /></property></bean>
    </beans>
  2. SpringBoot则是添加@EnableAsync注解
    @EnableAsync
    @SpringBootApplication
    @ServletComponentScan
    @MapperScan("com.cmc.schedule.model.mapper") //配置扫描mapper接口的地址
    public class NLPApplication extends SpringBootServletInitializer {//不使用springboot内嵌tomcat启动方式@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(NLPApplication.class);}public static void main(String[] args) {SpringApplication.run(NLPApplication.class, args);}//默认使用fastjson解析@Beanpublic HttpMessageConverters fastJsonHttpMessageConverters() {FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig = new FastJsonConfig();fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);fastConverter.setFastJsonConfig(fastJsonConfig);HttpMessageConverter<?> converter = fastConverter;return new HttpMessageConverters(converter);}
    }
  3. 这一步Spring和SpringBoot都是一样的,创建一个异步方法的类
    package com.cmc.tst;import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;/*** @Component 注解必须要有,否则无法将此bean注入* 当然也可以使用其他的注解,只要可以装配就行* * @author chenmc* @date 2017年9月4日 下午3:38:29*/
    @Component
    public class MyAsync {/*** @Async 表明这是一个异步方法,也就是说当调用这个方法时,* spring会创建一条线程来执行这个方法。* 注意:不能使用static来修饰此方法,否则@Async无效* * @author chenmc* @date 2017年9月4日 下午3:34:24*/@Asyncpublic void asyncMethod(){System.out.println(Thread.currentThread().getName());}
    }
  4. 测试调用异步方法,我这里使用的是JUnit4测试
        @AutowiredMyAsync async;@Testpublic void test() {System.out.println(Thread.currentThread().getName() + "start");//MyAsync async = new MyAsync(); //自己new出来的对象@Async将无效,必须要spring注入的async.asyncMethod();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "end");}
  5. 总结
    这里总结一下@Async注解无效的可能点
    一、异步方法使用static修饰
    二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
    三、测试异步方法不能与异步方法在同一个类中
    四、测试类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
    五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
  • 结语
    spring的@Async真的极大的方便了java的异步(多线程)开发,心里默念三遍:感谢spring!感谢spring!感谢spring!

Spring及SpringBoot @Async配置步骤及注意事项相关推荐

  1. SpringBoot线程池的创建、@Async配置步骤及注意事项

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:Muscleheng blog.csdn.net/Muscl ...

  2. Spring Boot 线程池的创建、@Async 配置步骤及注意事项

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:终于放弃了单调的swagger-ui了,选择了这款神器-knife4j个人原创+1博客:点击前往,查看更多 作者 ...

  3. IntelliJ IDEA 2017 MySQL5 绿色版 Spring 4 Mybatis 3 配置步骤详解(二)

    前言    继续上一篇安装教程 首先是MySQL绿色版安装之后其他组件安装,如果篇幅较长会分为多篇深入讲解,随笔属于学习笔记诸多错误还望指出 共同学习. MySQL 5.7 绿色版   我本地安装的是 ...

  4. spring访问oracle数据库表,Spring访问oracle数据库配置步骤

    1.spring 对数据库访问的支持 当我们开发持久层的时候,我们面临着多种选择,比如使用JDBC.Hibernate.java持久化API或其它持久化框架.幸好的是spring能够支持所有这些持久化 ...

  5. SpringBoot | 自动配置原理

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 这个月过去两天了,这篇文章才跟大家见面,最近比较累,大家见谅下.下班后闲着无聊看了下 SpringBoot 中的自动配置,把我 ...

  6. 【Spring框架家族】SpringBoot自动配置基本实现

    SpringBoot自动配置-Condition_1 Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载相应的Bean @Conditio ...

  7. springboot项目中的注解 启动项目的方式 解决spring的bean.xml配置不生效 spring的基础JDBC配置

    依赖 创建一个 Spring Boot 工程时,可以继承自一个 spring-boot-starter-parent ,也可以不继承 先来看 parent 的基本功能有哪些? 定义了 Java 编译版 ...

  8. 【Spring】SpringBoot 配置MySql和Doris多数据源

    嗨, 大家好, 最近公司想要使用DorisDB做数据存储, 经过几天对Doris的研究,发现Dorsi连接方式其实用的就是JDBC连接方式.今天把这两天的学习成果记录一下. 也希望对看到此文章的人有所 ...

  9. spring中基于XML的AOP配置步骤

    spring中基于XML的AOP配置步骤 IAccountService.java package com.itheima.service;/*** 账户的业务层接口*/ public interfa ...

最新文章

  1. 用oracle列实现sqlserver的自增列
  2. wxWidgets:wxOwnerDrawnComboBox类用法
  3. 搜索引擎链接算法之:HITS算法解析
  4. Spark官方调优文档翻译(转载)
  5. 既然开发了 飞鸽传书 就一定要帮助人
  6. 计算机网络之网络概述:4、分层结构(协议、接口、服务)
  7. C++读取XML树的建立和遍历
  8. 强制不使用“兼容性视图”的HTML代码
  9. DES加密算法(框图流程详细分析)(C++实现)
  10. saltstack python3_SaltStack事件驱动(3) – BEACONS
  11. 借贷系统后台操作说明
  12. 护理和计算机哪个专业好,护理专业考研的就业前景和方向
  13. 睿智的目标检测21——如何调用摄像头进行目标检测
  14. unity3D修改商店下载路径
  15. Python爬虫之HDU提交数据
  16. Qt生成二维码图片方法
  17. 单元测试整理(一)——单元测试是什么,有什么好处
  18. 利用osp.join()拼接文件名,利用f“{}“强制类型转换,利用osp.basename得到路径后面的文件名
  19. IDEA 的 show diagram 画出的类图线条乱了怎么办
  20. ORACLE匹配手机号,Oracle正则表达式语法介绍及实现手机号码匹配方法

热门文章

  1. python关联分析引擎_PowerBI x Python 之关联分析(上)
  2. Android下常见的内存泄露
  3. 原来Python破解受密码保护的zip文件这么简单,不保证一定成功
  4. 四十七、微信小程序开发页面结构WXML
  5. 三十七、细说Scrapy中的settings设置
  6. 百万奖金池!2022 全球人工智能技术创新大赛—算法挑战赛火热开启
  7. 直播预告 | 长文本知识抽取:基于语义分割的文档级三元组关系抽取
  8. ICCV 2021 | CMU朱俊彦团队:用一张草图轻松创建GAN模型
  9. 采样算法哪家强?一个针对主流采样算法的比较
  10. Fashion-MNIST数据集发布一周年,论文引用量超250篇