Springboot AOP 异步操作说明

1. 异步场景分析

在开发系统的过程中,通常会考虑到系统的性能问题,提升系统性能的一个重要思想
就是“串行”改“并行”。说起“并行”自然离不开“异步”,今天我们就来聊聊如何使用
Spring的 @Async的异步注解。

2. Spring 业务的异步实现

2.1 启动异步配置

在基于注解方式的配置中,借助@EnableAsync注解进行异步启动声明,Spring
Boot版的项目中,将@EnableAsync注解应用到启动类上, 代码示例如下:

@EnableAsync //spring容器启动时会创建线程池
@SpringBootApplication
public class Application {
	public static void main(String[] args ) {
		SpringApplication. run (Application. class , args );
	}
}

2.2 Spring中@Async注解应用

在需要异步执行的业务方法上,使用@Async方法进行异步声明。

@Async
@Transactional (propagation = Propagation. REQUIRES_NEW )
@Override
public void saveObject(SysLog entity ) {
	System. out .println("SysLogServiceImpl.save:" + Thread. currentThread().getName());
	sysLogDao .insertObject( entity );
	// try {Thread. sleep (5000);} catch (Exception e ) {}
}

假如需要获取业务层异步方法的执行结果,可参考如下代码设计进行实现:


@Transactional (propagation = Propagation. REQUIRES_NEW )
@Async
@Override
public Future<Integer> saveObject(SysLog entity ) {
	System. out .println("SysLogServiceImpl.save:"+ Thread. currentThread ().getName());
	int rows = sysLogDao .insertObject( entity );
	// try {Thread. sleep (5000);} catch (Exception e ) {}
	return new AsyncResult<Integer>( rows );
}

其中,AsyncResult对象可以对异步方法的执行结果进行封装,假如外界需要异步方
法结果时,可以通过Future对象的get方法获取结果。
当我们需要自己对spring框架提供的线程池进行一些简易配置,可以参考如下代码:

spring:
	task:
		execution:
			pool:
			queue-capacity: 128
			core-size: 5
			max-size: 128
			keep-alive: 60000
		thread-name-prefix: db-service-task-

对于spring框架中线程池配置参数的涵义,可以参考ThreadPoolExecutor对象中的
解释。
说明:对于@Async注解默认会基于ThreadPoolTaskExecutor对象获取工作线程,然
后调用由@Async描述的方法,让方法运行于一个工作线程,以实现异步操作。但是假如系
统中的默认拒绝处理策略,任务执行过程的异常处理不能满足我们自身业务需求的话,我可
以对异步线程池进行自定义.(SpringBoot中默认的异步配置可以参考自动配置对象
TaskExecutionAutoConfiguration).

3. Spring 自定义异步池的实现

为了让Spring中的异步池更好的服务于我们的业务,同时也尽量避免OOM,可以自定义
线程池优化设计如下:关键代码如下:

package com.cy.pj.common.config
@Slf4j
@Setter
@Configuration
@ConfigurationProperties( "async-thread-pool" )
public class SpringAsyncConfig implements AsyncConfigurer{
	/**核心线程数*/
	private int corePoolSize =20;
	/**最大线程数*/
	private int maximumPoolSize=1000;
	/**线程空闲时间*/
	private int keepAliveTime =30;
	/**阻塞队列容量*/
	private int queueCapacity =200;
	/**构建线程工厂*/
	private ThreadFactory threadFactory = new ThreadFactory() {
		//CAS算法
		private AtomicInteger at = new AtomicInteger(1000);
		@Override
		public Thread newThread(Runnable r ) {
			return new Thread( r , "db-async-thread-" + at .getAndIncrement());
		}
	};
	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor .setCorePoolSize( corePoolSize );
		executor .setMaxPoolSize( maximumPoolSize );
		executor .setKeepAliveSeconds( keepAliveTime );
		executor .setQueueCapacity( queueCapacity );
		executor .setRejectedExecutionHandler((Runnable r ,
		ThreadPoolExecutor exe ) -> { 
			log .warn( "当前任务线程池队列已满." );
		});
		executor .initialize();
		return executor ;
	}
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return new AsyncUncaughtExceptionHandler() {
			@Override
			public void handleUncaughtException(Throwable ex ,
				Method method , Object... params ) { log .error( "线程池执行任务发生未知异常." , ex );
			}
		};
	}
}

其中:@ConfigurationProperties(“async-thread-pool”)的含义是读取
application.yml配置文件中以"async-thread-pool"名为前缀的配置信息,并通过所描
述类的set方法赋值给对应的属性,在application.yml中连接器池的关键配置如下:

async-thread-pool:
	corePoolSize: 20
	maxPoolSize: 1000
	keepAliveSeconds: 30
	queueCapacity: 1000

后续在业务类中,假如我们使用@Async注解描述业务方法,默认会使用
ThreadPoolTaskExecutor池对象中的线程执行异步任务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值