使用Spring开启@Async异步方式(javaconfig配置)

目录
  • Spring开启@Async异步(javaconfig配置)
    • 应用场景
    • 创建AsyncTask
    • 创建spring配置AppConfig
    • 测试
  • Spring @Async Demo

Spring开启@Async异步(javaconfig配置)

在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。

应用场景

  • 某些耗时较长的而用户不需要等待该方法的处理结果
  • 某些耗时较长的方法,后面的程序不需要用到这个方法的处理结果时

代码

创建AsyncTask

/**
 * 异步任务
 *
 * @author Peng
 */
public class AsyncTask {
    @Async
    public void doAsyncTask() throws InterruptedException {
        // 假设执行一个很耗时的任务
        Thread.sleep(10 * 1000);
        System.out.println("执行完成,我执行了10秒");
    }
}

创建spring配置AppConfig

/**
 * spring 配置
 *
 * @author Peng
 */
@Configuration
@EnableAsync
public class AppConfig {
    /**
     * 声明异步任务bean
     *
     * @return
     */
    @Bean
    public AsyncTask asyncTask() {
        return new AsyncTask();
    }
}

测试

/**
 * 异步测试
 *
 * @author Peng
 */
public class AppTest {
    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        AsyncTask task = ctx.getBean(AsyncTask.class);
        task.doAsyncTask();
        System.out.println("异步任务调用成功,返回客户端执行成功,异步任务继续执行");
    }
}

执行结果

异步任务调用成功,返回客户端执行成功,异步任务继续执行

执行完成,我执行了10秒

从结果可以看出,异步任务测试成功!

Spring @Async Demo

模拟一个业务场景:系统新用户注册成功后,异步发送邮件。

Project Directory

Maven Dependency

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>org.fool.springasync</groupId>
	<artifactId>springasync</artifactId>
	<name>springasync</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<org.springframework-version>4.2.8.RELEASE</org.springframework-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.8.1</version>
		</dependency>
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>19.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>
		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<version>2.3.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.10</version>
				<configuration>
					<additionalProjectnatures>
						<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
					</additionalProjectnatures>
					<additionalBuildcommands>
						<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
					</additionalBuildcommands>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<compilerArgument>-Xlint:all</compilerArgument>
					<showWarnings>true</showWarnings>
					<showDeprecation>true</showDeprecation>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.eclipse.jetty</groupId>
				<artifactId>jetty-maven-plugin</artifactId>
				<version>9.3.11.v20160721</version>
				<configuration>
					<scanIntervalSeconds>10</scanIntervalSeconds>
					<httpConnector>
						<port>8888</port>
					</httpConnector>
					<webApp>
						<contextPath>/springasync</contextPath>
					</webApp>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

root-context.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- Root Context: defines shared resources visible to all other web components -->
</beans>

servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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">
	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />
	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources
		directory -->
	<resources mapping="/resources/**" location="/resources/" />
	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	<context:component-scan base-package="org.fool.springasync" />
</beans:beans>

AsyncConfig.java

package org.fool.springasync;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
@PropertySource("classpath:async.properties")
public class AsyncConfig {
	/** Set the ThreadPoolExecutor's core pool size. */
	@Value("${core.pool.size}")
    private Integer corePoolSize;

    /** Set the ThreadPoolExecutor's maximum pool size. */
	@Value("${max.pool.size}")
    private Integer maxPoolSize;

    /** Set the capacity for the ThreadPoolExecutor's BlockingQueue. */
	@Value("${queue.capacity}")
    private Integer queueCapacity;  

	@Value("${thread.name.prefix}")
    private String ThreadNamePrefix;

	@Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfig() {
        return new PropertySourcesPlaceholderConfigurer();
    } 

    @Bean
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix(ThreadNamePrefix);  

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

Note:

AsyncConfig使用Annotation进行Spring Async的配置,当然也可以用XML的方式进行配置,只需要在servlet-context.xml中添加task的命名空间,同时加下如下两行配置:

<!-- Enables Spring Async -->
<task:annotation-driven executor="asyncExecutor"/>
<task:executor id="asyncExecutor" pool-size="2-4" queue-capacity="10"/>

<task:executor />配置参数:

id:当配置多个executor时,被@Async("id")指定使用;也被作为线程名的前缀。

pool-size:

  • core size:最小的线程数,缺省:1
  • max size:最大的线程数,缺省:Integer.MAX_VALUE

queue-capacity:当最小的线程数已经被占用满后,新的任务会被放进queue里面,当这个queue的capacity也被占满之后,pool里面会创建新线程处理这个任务,直到总线程数达到了max size,这时系统会拒绝这个任务并抛出TaskRejectedException异常(缺省配置的情况下,可以通过rejection-policy来决定如何处理这种情况)。缺省值为:Integer.MAX_VALUE

keep-alive:超过core size的那些线程,任务完成后,再经过这个时长(秒)会被结束掉

rejection-policy:当pool已经达到max size的时候,如何处理新任务

  • ABORT(缺省):抛出TaskRejectedException异常,然后不执行
  • DISCARD:不执行,也不抛出异常
  • DISCARD_OLDEST:丢弃queue中最旧的那个任务
  • CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行

MailService.java

package org.fool.springasync;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class MailService {

	@Async
	public void sendMail(String username) {
		System.out.println("Send Mail initialization...");
		System.out.println("Execute method asynchronously - " + Thread.currentThread().getName());

		try {
			Thread.sleep(5000);
			System.out.println("Welcome " + username);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("Send Mail Async done!!!");
	}
}

User.java

package org.fool.springasync;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class User {
	private Long id;
	private String username;
	private String password;
	public User() {
	}

	public User(Long id, String username, String password) {
		this.id = id;
		this.username = username;
		this.password = password;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
	}
}

UserService.java

package org.fool.springasync;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
@Service
public class UserService {
	@Inject
	private MailService mailService;
	public void registerUser(User user) {
		System.out.println("insert user to db...");
		mailService.sendMail(user.getUsername());
		System.out.println("register done, please check the email later!!!");
	}
}

UserController.java

package org.fool.springasync;
import javax.inject.Inject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {
	@Inject
	private UserService userService;
	@RequestMapping(value = "/testasync", method = RequestMethod.POST)
	@ResponseBody
	public User register(@RequestBody User user) {
		System.out.println(user);
		userService.registerUser(user);
		return user;
	}
}

Test

http://localhost:8888/springasync/user/testasync

POST请求(send两次)

Console Output

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java Spring之@Async原理案例详解

    目录 前言 一.如何使用@Async 二.源码解读 总结 前言 用过Spring的人多多少少也都用过@Async注解,至于作用嘛,看注解名,大概能猜出来,就是在方法执行的时候进行异步执行. 一.如何使用@Async 使用@Async注解主要分两步: 1.在配置类上添加@EnableAsync注解 @ComponentScan(value = "com.wang") @Configuration @EnableAsync public class AppConfig { } 2.在想要异

  • Java @Async注解导致spring启动失败解决方案详解

    前言 在这篇文章里,最后总结处,我说了会讲讲循环依赖中,其中一个类添加@Async有可能会导致注入失败而抛异常的情况,今天就分析一下. 一.异常表现,抛出内容 1.1循环依赖的两个class 1.CycleService1 @Service public class CycleService1 { @Autowired private CycleService2 cycleService2; @WangAnno @Async public void doThings() { System.out

  • JAVA 中Spring的@Async用法总结

    JAVA 中Spring的@Async用法总结 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后,就已经内置了@Async来完美解决这个问题,本文将完成介绍@Async的用法. 1.  何为异步调用? 在解释异步调用之前,我们先来看同步调用的定义:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果. 异步调用则是只是发送了调用的

  • 使用Spring开启@Async异步方式(javaconfig配置)

    目录 Spring开启@Async异步(javaconfig配置) 应用场景 创建AsyncTask 创建spring配置AppConfig 测试 Spring @Async Demo Spring开启@Async异步(javaconfig配置) 在Spring中,基于@Async标注的方法,称之为异步方法:这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作. 应用场景 某些耗时较长的而用户不需要等待该方法的处理结果 某些耗时较长的方法,后面的程序不需要

  • 如何在Spring中使用编码方式动态配置Bean详解

    bean与spring容器的关系 Bean配置信息定义了Bean的实现及依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据注册表加载.实例化Bean,并建立Bean和Bean的依赖关系,最后将这些准备就绪的Bean放到Bean缓存池中,以供外层的应用程序进行调用. 本文将给大家详细介绍关于在Spring中使用编码方式动态配置Bean的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 1 DefaultListableBea

  • Spring Boot @Async 异步任务执行方法

    1.任务执行和调度 Spring用TaskExecutor和TaskScheduler接口提供了异步执行和调度任务的抽象. Spring的TaskExecutor和java.util.concurrent.Executor接口时一样的,这个接口只有一个方法execute(Runnable task). 1.1.TaskExecutor类型 Spring已经内置了许多TaskExecutor的实现,你没有必要自己去实现: SimpleAsyncTaskExecutor  这种实现不会重用任何线程,

  • Spring Boot Async异步执行任务过程详解

    异步调用就是不用等待结果的返回就执行后面的逻辑,同步调用则需要等带结果再执行后面的逻辑. 通常我们使用异步操作都会去创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行,代码如下: ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(() -> { try { // 业务逻辑 } catch (Exception e) { e.printStackTrace(

  • Spring Boot之@Async异步线程池示例详解

    目录 前言 一. Spring异步线程池的接口类 :TaskExecutor 二.简单使用说明 三.定义通用线程池 1.定义线程池 2.异步方法使用线程池 3.通过xml配置定义线程池 四.异常处理 五.问题 前言 很多业务场景需要使用异步去完成,比如:发送短信通知.要完成异步操作一般有两种: 1.消息队列MQ 2.线程池处理. 我们来看看Spring框架中如何去使用线程池来完成异步操作,以及分析背后的原理. 一. Spring异步线程池的接口类 :TaskExecutor 在Spring4中,

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

    在前面的博客中,http://www.jb51.net/article/106718.htm 我们使用了spring boot的异步操作,当时,我们使用的是默认的线程池,但是,如果我们想根据项目来定制自己的线程池了,下面就来说说,如何定制线程池! 一.增加配置属性类 package com.chhliu.springboot.async.configuration; import org.springframework.boot.context.properties.ConfigurationP

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

    目录 一.增加配置属性类 二.创建线程池 三.在主类中开启配置支持 四.测试类 五.测试 六.配置默认的线程池 在前面的博客中,//www.jb51.net/article/106718.htm 我们使用了spring boot的异步操作,当时,我们使用的是默认的线程池,但是,如果我们想根据项目来定制自己的线程池了,下面就来说说,如何定制线程池! 一.增加配置属性类 package com.chhliu.springboot.async.configuration; import org.spr

  • Spring中@Async注解实现异步调详解

    异步调用 在解释异步调用之前,我们先来看同步调用的定义:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果. 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕,继续执行下面的流程.例如, 在某个调用中,需要顺序调用 A, B, C三个过程方法:如他们都是同步调用,则需要将他们都顺序执行完毕之后,过程才执行完毕: 如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了. 概述说明 Sp

  • Spring中的使用@Async异步调用方法

    目录 使用@Async异步调用方法 Async简介 给Spring的TaskExecutor去完成 本次记录Async使用场景 异步请求与异步调用的区别 异步请求的实现 SpringBoot中异步调用的使用 使用@Async异步调用方法 Async简介 异步方法调用使用场景:处理日志.发送邮件.短信...... spring中提供了@Async来实现异步方法. @Async修饰类,则该类所有方法都是异步的,@Async修饰方法,则该方法是异步的. 被修饰的方法在被调用时,会在一个新的线程中执行.

  • 浅谈Spring @Async异步线程池用法总结

    本文介绍了Spring @Async异步线程池用法总结,分享给大家,希望对大家有帮助 1. TaskExecutor spring异步线程池的接口类,其实质是Java.util.concurrent.Executor Spring 已经实现的异常线程池: 1. SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程. 2. SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作.只适用于不需要多线程的地方 3. Conc

随机推荐