信息发布→ 登录 注册 退出

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

发布时间:2026-01-11

点击量:
目录
  • 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

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

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!