springboot项目如何支持(Async异步任务)

 

为什么需要异步任务呢?

1、假如向服务端发送一个请求(假设:给批量给用户发邮件或者短信通知或者批量消息推送),由于底层用户量基数很大,如果客户端同步发起指令后长时间等待,会造成客户端连接time out,或者等待超时的请求,这种需求一般客户端不需要全部

等会所有底层业务执行完毕,只需要接收操作成功或者命令已执行的指令。这种就需要使用异步操作。

  • 一般场景下,我们会使用多线程的方式,发送请求后,重新开启一个线程去执行;(异步线程)这个能够达到我们的目的。
  • 今天记录一下使用spring 3.X 以后提供的注解
    @EnableAysnc、@Aysnc

项目准备(基于springboot)

pom.xml依赖引入

<dependencies>
	
	<!--引入springbooweb,他会根据依赖引入springboot相关包-->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
		<version>2.2.2.RELEASE</version>
	</dependency>
	
	<!--这个不是必须,这个是一个非常强大的工具包-->
	<dependency>
		<groupId>cn.hutool</groupId>
		<artifactId>hutool-all</artifactId>
		<version>5.5.8</version>
	</dependency>
	<!--这个是一个不需要写get/set等快捷编码,写上相关注释后,编译器会自动生成代码,快速开发,代码简洁需要-->
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.18.18</version>
	</dependency>
</dependencies>

配置文件(yml)

application.yml配置文件名称

可以有可以没有,这个如果要自己重新指定端口子类的,重新定义就行了。
--我这里就啥不管,启动后默认端口就是8080
--如果要重新制定,这样就行了
server:
  port: 8080

代码编写

主启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync// 开启异步注解功能【必须要开启,否则异步任务不起作用】
public class MainRun {

    public static void main(String[] args) {
        SpringApplication.run(MainRun.class, args);
    }
}

为什么呢?因为@EnableAsync注解里面导入了AsyncConfigurationSelector到容器,这样就会自动识别@Async注解,开启异步任务支持了。

@Import(AsyncConfigurationSelector.class)

业务代码编写(controller)

import com.wolf.boy.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    @GetMapping("/hello")
    public Object hello() {
        asyncService.hello();
        return "success 处理成功";
    }
    @GetMapping("/simpleHello")
    public Object simpleHello() {
        asyncService.simpleHello();
        return "simpleHello 处理成功";
    }
}

业务代码编写(asyncService)

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
*
* 都是利用线程睡眠,模拟系统处理时间消耗
*/
@Service
public class AsyncService {

    @Async  // 表示这是一个异步方法,再线程池中获取一个线程来单独执行该方法
    public void hello() {
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("处理数据中..");
    }

    //普通方法
    public void simpleHello() {
        try {
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("处理数据中..");
    }
}

测试用例

启动程序后,访问

localhost:8080/hello 可以看到客户端马上能够收到服务端响应。通过代码可以看见这里调用的是一个加了注解@Async的方法,说明这是一个异步方法,验证是成功的;

在输入

localhost:8080/simpleHello 这个访问后,浏览器一直等待服务端响应,由于服务端处理需要3秒以后才会执行业务处理,所以浏览器等待三秒以后才会看到服务端给予客户端的数据响应;

到此为止,异步任务的支持就完成了。

源码学习和理解一下,这个到底怎么执行的。

  • 加入异步任务支持后,比如异步任务总的有线程池去执行,否则你加了又有什么用。
  • 在springboot的spring-boot-autoconfigure包中,可以看到有一个对线程池的初始化AutoConfiguation类叫(TaskExecutionAutoConfiguration)

import java.util.concurrent.Executor;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties.Shutdown;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.boot.task.TaskExecutorCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.task.TaskDecorator;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}.
 *
 * @author Stephane Nicoll
 * @author Camille Vienot
 * @since 2.1.0
 */
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {

	/**
	 * Bean name of the application {@link TaskExecutor}.
	 */
	public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";

	@Bean
	@ConditionalOnMissingBean
	public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
			ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
			ObjectProvider<TaskDecorator> taskDecorator) {
		TaskExecutionProperties.Pool pool = properties.getPool();
		TaskExecutorBuilder builder = new TaskExecutorBuilder();
		builder = builder.queueCapacity(pool.getQueueCapacity());
		builder = builder.corePoolSize(pool.getCoreSize());
		builder = builder.maxPoolSize(pool.getMaxSize());
		builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());
		builder = builder.keepAlive(pool.getKeepAlive());
		Shutdown shutdown = properties.getShutdown();
		builder = builder.awaitTermination(shutdown.isAwaitTermination());
		builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
		builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
		builder = builder.customizers(taskExecutorCustomizers.orderedStream()::iterator);
		builder = builder.taskDecorator(taskDecorator.getIfUnique());
		return builder;
	}

	//这里就通过上面创建的TaskExecutorBuilder构造器使用build方法,创建了一个ThreadPoolTaskExecutor
	@Lazy
	@Bean(name = { APPLICATION_TASK_EXECUTOR_BEAN_NAME,
			AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME })
	@ConditionalOnMissingBean(Executor.class)
	public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {
		return builder.build();
	}

}

当然你也可以根据需要自定义线程池

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值