• 前言

    最近在做一个用户反馈的功能,就是当用户反馈意见或建议后服务端将意见保存然后发邮件给相关模块的开发者。考虑发邮件耗时的情况所以我想用异步的方法去执行,于是就开始研究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.xsd
                            http://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启动方式
    	@Override
    	protected SpringApplicationBuilder configure(
    			SpringApplicationBuilder application) {
    		return application.sources(NLPApplication.class);
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(NLPApplication.class, args);
    	}
    
    	//默认使用fastjson解析
    	@Bean
    	public 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
    	 */
    	@Async
    	public void asyncMethod(){
    		System.out.println(Thread.currentThread().getName());
    	}
    }
  4. 测试调用异步方法,我这里使用的是JUnit4测试
    	@Autowired
    	MyAsync async;
    
    	@Test
    	public 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配置步骤及注意事项

    最近在做订单模块,用户购买服务类产品之后,需要进行预约,预约成功之后分别给商家和用户发送提醒短信.考虑发短信耗时的情况所以我想用异步的方法去执行,于是就在网上看见了Spring的@Async了. 但是 ...

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

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

  3. SpringBoot自定义配置步骤

    1. 在yml中填写自定义配置 ly: sms: accessKeyId: # 短信配置 accessKeySecret: signName: xx商城 # 签名名称 verifyCodeTempla ...

  4. 整合struts2+hibernate详细配置步骤及注意事项

    刚刚学完这两个框架,就迫不及待的做了一个例子,在整合两个框架的时候,也碰到了一些小问题,下面介绍一下配置的步骤: 1.创建一个自定义的struts2和hibernate的类库 因为之前写例子都是直接将 ...

  5. spring-boot @Async 的使用、自定义Executor的配置方法

    1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent.Executor Spring 已经实现的异常线程池: 1. SimpleAsyncT ...

  6. spring boot使用自定义配置的线程池执行Async异步任务

    一.增加配置属性类 package com.chhliu.springboot.async.configuration; import org.springframework.boot.context ...

  7. SpringBoot 自动配置:Spring Data JPA

    前言 不知道从啥时候开始项目上就一直用MyBatis,其实我个人更新JPA些,因为JPA看起来OO的思想更强烈些,所以这才最近把JPA拿出来再看一看,使用起来也很简单,除了定义Entity实体外,声明 ...

  8. spring基于xml的声明式事务控制配置步骤

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  9. SpringBoot 优雅配置跨域多种方式及Spring Security跨域访问配置的坑

    前言 最近在做项目的时候,基于前后端分离的权限管理系统,后台使用 Spring Security 作为权限控制管理, 然后在前端接口访问时候涉及到跨域,但我怎么配置跨域也没有生效,这里有一个坑,在使用 ...

随机推荐

  1. 抓取某东的TT购买记录分析TT购买趋势

    最近学习了一些爬虫技术,想做个小项目检验下自己的学习成果,在逛某东的时候,突然给我推荐一个TT的产品,点击进去浏览一番之后就产生了抓取TT产品,然后进行数据分析,看下那个品牌的TT卖得最好. 本文通过 ...

  2. ubuntu 16.04 安装 vscode

    ubuntu 安装 vscode sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make sudo apt-get update sudo apt ...

  3. Cookie、cookie使用方法

    Cookie.cookie使用方法.保存用户名密码 //设置Cookie, //cname 获取时所需参数 //username,password 用于记住账号密码,如果只要存一个参数 passwor ...

  4. Array库

    /** * 查找元素在数组中出现的所有位置 * @param {要查找的数组} array * @param {要查找的元素} ele * @param {回调函数} callback */ func ...

  5. 我的第一个.NET Core App Windows系统

    一.前言 本篇开发环境?1.操作系统: Windows 10 X642.SDK: .NET Core 2.0 Preview 二.安装 .NET Core SDK 1.下载 .NET Core下载地址 ...

  6. Adams 2013自定义插件方法zz

    1.Adams插件介绍 Adams的高级模块(如Controls控制模块.Vibration振动模块.Durability耐久性模块等)是以插件的形式集成在Adams软件中.通过Adams提供的插件管 ...

  7. 微信跳转,wap网页跳转微信打开指定页面

    最近一朋友的客户有这么一需求,wap网页跳转微信打开指定页面,让用户去关注公众号.想这么干,通过网页跳转到微信并打开带有二维码的网页,用户长按识别二维码就可以关注了.想法很好,于是去搜索了“微信跳转, ...

  8. 190327 Python登录接口

    #!Author:John # _*_ coding: utf-8 _*_ #编写登录接口 #输入用户名密码 #认证成功后显示欢迎信息 #输错三次后锁定 import sys, os, getpass ...

  9. vue 图片预览插件

    https://github.com/daidaitu1314/vue2-preview //cnpm cnpm install vue2-preview -save //引入 import VueP ...

  10. 微信网页悬浮窗交互效果的web实现

    一.微信的悬浮窗交互效果 微信更新后,发现多了个悬浮窗功能.公众号阅读,网页浏览回退后默认会出现.再点击,可以回到刚才阅读的地方.于是,再也不会遇到回复老婆的信息,再切换回来重新找刚才阅读东西的麻烦了 ...