Spring开启@Async异步(javaconfig配置)
在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。
应用场景
某些耗时较长的而用户不需要等待该方法的处理结果 某些耗时较长的方法,后面的程序不需要用到这个方法的处理结果时代码
创建AsyncTask
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * 异步任务 * * @author Peng */ public class AsyncTask { @Async public void doAsyncTask() throws InterruptedException { // 假设执行一个很耗时的任务 Thread.sleep( 10 * 1000 ); System.out.println( "执行完成,我执行了10秒" ); } } |
创建spring配置AppConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
/** * spring 配置 * * @author Peng */ @Configuration @EnableAsync public class AppConfig { /** * 声明异步任务bean * * @return */ @Bean public AsyncTask asyncTask() { return new AsyncTask(); } } |
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * 异步测试 * * @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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
<? xml version = "1.0" encoding = "UTF-8" ?> < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://HdhCmsTestw3.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测试数据mons</ 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<? xml version = "1.0" encoding = "UTF-8" ?> < web-app xmlns:xsi = "http://HdhCmsTestw3.org/2001/XMLSchema-instance" xmlns = "http://java.sun测试数据/xml/ns/javaee" xmlns:web = "http://java.sun测试数据/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation = "http://java.sun测试数据/xml/ns/javaee http://java.sun测试数据/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
1 2 3 4 5 6 7 |
<? xml version = "1.0" encoding = "UTF-8" ?> < beans xmlns = "http://HdhCmsTestspringframework.org/schema/beans" xmlns:xsi = "http://HdhCmsTestw3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://HdhCmsTestspringframework.org/schema/beans http://HdhCmsTestspringframework.org/schema/beans/spring-beans.xsd" >
<!-- Root Context: defines shared resources visible to all other web components --> </ beans > |
servlet-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<? xml version = "1.0" encoding = "UTF-8" ?> < beans:beans xmlns = "http://HdhCmsTestspringframework.org/schema/mvc" xmlns:xsi = "http://HdhCmsTestw3.org/2001/XMLSchema-instance" xmlns:beans = "http://HdhCmsTestspringframework.org/schema/beans" xmlns:context = "http://HdhCmsTestspringframework.org/schema/context" xmlns:task = "http://HdhCmsTestspringframework.org/schema/task" xsi:schemaLocation="http://HdhCmsTestspringframework.org/schema/mvc http://HdhCmsTestspringframework.org/schema/mvc/spring-mvc.xsd http://HdhCmsTestspringframework.org/schema/beans http://HdhCmsTestspringframework.org/schema/beans/spring-beans.xsd http://HdhCmsTestspringframework.org/schema/context http://HdhCmsTestspringframework.org/schema/context/spring-context.xsd http://HdhCmsTestspringframework.org/schema/task http://HdhCmsTestspringframework.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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
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的命名空间,同时加下如下两行配置:
1 2 3 |
<!-- 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_VALUEqueue-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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package org.fool.springasync; import org.apache测试数据mons.lang3.builder.ToStringBuilder; import org.apache测试数据mons.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
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
原文链接:https://retry.blog.csdn.net/article/details/79014329
查看更多关于使用Spring开启@Async异步方式(javaconfig配置)的详细内容...