spring中异步任务源码分析

目录

前言

一、@EnableAsync 

二、AsyncAnnotationBeanPostProcessor

三、AsyncExecutionInterceptor

四、自定义异步线程池

五、TaskDecorator

总结


前言

       在spring框架中,我们可以使用async注解实现方法的异步执行,但是如果不了解内部源码的运行机制,也会导致很多问题,比如默认线程池的问题,async导致循环依赖报错的问题等,本篇文章主要分析async任务执行的全流程,并给出自定义异步线程池的方法,关于循环依赖相关内容会在下篇文章中给出。


一、@EnableAsync 

        首先从EnableAsync注解进行分析,主要是引入了ProxyAsyncConfiguration类。

@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {}

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

	@Override
	public String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {ProxyAsyncConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}
}

           ProxyAsyncConfiguration本身是一个Configuration类,通过@Bean的方式引入了AsyncAnnotationBeanPostProcessor。

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
		Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
		AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
		//将ProxyAsyncConfiguration中的executor赋值给AsyncAnnotationBeanPostProcessor,executor通过AbstractAsyncConfiguration中的setConfigurers方法
		//在自定义的AsyncConfigurer类中的getAsyncExecutor方法获取。
		if (this.executor != null) {
			bpp.setExecutor(this.executor);
		}
		if (this.exceptionHandler != null) {
			bpp.setExceptionHandler(this.exceptionHandler);
		}
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}
}

        ProxyAsyncConfiguration继承了AbstractAsyncConfiguration ,同样是一个Configuration类,通过setConfigurers调用容器中的AsyncConfigurer的getAsyncExecutor方法,可以创建自定义线程池。这个方法的在registerBeanPostProcessors中创建AsyncAnnotationBeanPostProcessor 时调用,此时可以保证容器内的beandefination已经加载完毕,可以确保自定义异步线程池已经在容器中。

@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {
	protected Executor executor;
	protected AsyncUncaughtExceptionHandler exceptionHandler;
	/**
	 * Collect any {@link AsyncConfigurer} beans through autowiring.
	 * 自动注入容器中的AsyncConfigurer
	 */
	@Autowired(required = false)
	void setConfigurers(Collection<AsyncConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one AsyncConfigurer may exist");
		}
		AsyncConfigurer configurer = configurers.iterator().next();
		//调用容器中的AsyncConfigurer的getAsyncExecutor方法,可以在此处构建自定义异步线程池
		this.executor = configurer.getAsyncExecutor();
		this.exceptionHandler = configurer.getAsyncUncaughtExceptionHandler();
	}

}

二、AsyncAnnotationBeanPostProcessor

       在AsyncAnnotationBeanPostProcessor初始化的过程中,由于实现了BeanFactoryAware接口,所以会调用setBeanFactory方法。

exposedObject = initializeBean(beanName, exposedObject, mbd);
invokeAwareMethods(beanName, bean);
	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			//调用setBeanFactory方法
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

         在setBeanFactory方法中主要创建了一个AsyncAnnotationAdvisor对象,为后面的代理做准备。

	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		//创建advisor,将AsyncAnnotationBeanPostProcessor中的引入线程池赋值给AnnotationAsyncExecutionInterceptor的默认线程池
		AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
		if (this.asyncAnnotationType != null) {
			advisor.setAsyncAnnotationType(this.asyncAnnotationType);
		}
		advisor.setBeanFactory(beanFactory);
		this.advisor = advisor;
	}
}

         在构建AsyncAnnotationAdvisor对象的过程中引入了AnnotationAsyncExecutionInterceptor,这也时后续执行过程中的拦截器。

	public AsyncAnnotationAdvisor(Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {
		//构建切面切点
		this.advice = buildAdvice(executor, this.exceptionHandler);
		this.pointcut = buildPointcut(asyncAnnotationTypes);
	}

	protected Advice buildAdvice(Executor executor, AsyncUncaughtExceptionHandler exceptionHandler) {
		return new AnnotationAsyncExecutionInterceptor(executor, exceptionHandler);
	}

        AbstractAdvisingBeanPostProcessor的postProcessAfterInitialization方法中完成了代理对象创建。

wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (bean instanceof AopInfrastructureBean) {
			// Ignore AOP infrastructure such as scoped proxies.
			return bean;
		}
		if (bean instanceof Advised) {
			Advised advised = (Advised) bean;
			if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
				// Add our local Advisor to the existing proxy's Advisor chain...
				if (this.beforeExistingAdvisors) {
					advised.addAdvisor(0, this.advisor);
				}
				else {
					advised.addAdvisor(this.advisor);
				}
				return bean;
			}
		}
		if (isEligible(bean, beanName)) {
			//基于advisor创建代理对象
			ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
			if (!proxyFactory.isProxyTargetClass()) {
				evaluateProxyInterfaces(bean.getClass(), proxyFactory);
			}
			proxyFactory.addAdvisor(this.advisor);
			customizeProxyFactory(proxyFactory);
			return proxyFactory.getProxy(getProxyClassLoader());
		}
		// No proxy needed.
		return bean;
	}

三、AsyncExecutionInterceptor

        执行的主要逻辑在AsyncExecutionInterceptor的invoke方法,基本就是构建Callable对象,然后放入线程池中执行。

	public Object invoke(final MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
		final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
		//确定异步线程池
		AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
		if (executor == null) {
			throw new IllegalStateException(
					"No executor specified and no default executor set on AsyncExecutionInterceptor either");
		}
		//构建异步任务
		Callable<Object> task = new Callable<Object>() {
			@Override
			public Object call() throws Exception {
				try {
					Object result = invocation.proceed();
					if (result instanceof Future) {
						return ((Future<?>) result).get();
					}
				}
				return null;
			}
		};
		//执行任务
		return doSubmit(task, executor, invocation.getMethod().getReturnType());
	}

        获取线程池首先获取异步拦截器的默认线程池,也就是拦截器创建时赋值的默认线程池,没有赋值时获取容易内的默认线程池,如果没有就会新建线程池。

	protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
		AsyncTaskExecutor executor = this.executors.get(method);
		if (executor == null) {
			}
			else {
				//获取配置的异步线程池
				targetExecutor = this.defaultExecutor;
				if (targetExecutor == null) {
					synchronized (this.executors) {
						if (this.defaultExecutor == null) {
							//获取默认线程池,没有的话自行创建SimpleAsyncTaskExecutor,但是SimpleAsyncTaskExecutor每次提交都会开启新线程,最好添加自己的线程池
							//在beanFactory中获取TaskExecutor,需要让当前bean能够感知beanFactory,所以需要实现BeanFactoryAware接口
							this.defaultExecutor = getDefaultExecutor(this.beanFactory);
						}
						targetExecutor = this.defaultExecutor;
					}
				}
			}
			this.executors.put(method, executor);
		}
		return executor;
	}

       spring默认创建的是SimpleAsyncTaskExecutor线程池,该线程池在执行任务的时候会直接新建一个线程执行,且没有线程数上限,不宜使用。

	protected Executor getDefaultExecutor(BeanFactory beanFactory) {
		//获取容器中的TaskExecutor类
		Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
		//新建SimpleAsyncTaskExecutor线程池
		return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
	}
	protected void doExecute(Runnable task) {
		//新建线程执行
		Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
		thread.start();
	}
	public Thread createThread(Runnable runnable) {
		Thread thread = new Thread(getThreadGroup(), runnable, nextThreadName());
		thread.setPriority(getThreadPriority());
		thread.setDaemon(isDaemon());
		return thread;
	}

        根据异步任务不同的返回值形式,会调用不同的方法执行任务。

	protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
		if (completableFuturePresent) {
			Future<Object> result = CompletableFutureDelegate.processCompletableFuture(returnType, task, executor);
			if (result != null) {
				return result;
			}
		}
		//返回值是ListenableFuture
		if (ListenableFuture.class.isAssignableFrom(returnType)) {
			return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
		}
		//返回值是Future
		else if (Future.class.isAssignableFrom(returnType)) {
			return executor.submit(task);
		}
		//没有返回值
		else {
			executor.submit(task);
			return null;
		}
	}

四、自定义异步线程池

       在执行在实际项目中,一般通过继承AsyncConfigureSupport的方式,指定程序中使用的异步线程池,从而避免使用默认的线程池。

public class AsyncExecutorConfig extends AsyncConfigurerSupport  {

    //设置异步线程池
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(20);
        //配置最大线程数
        executor.setMaxPoolSize(50);
        //配置队列大小
        executor.setQueueCapacity(999);
        executor.setKeepAliveSeconds(60 * 15);
        executor.setThreadNamePrefix("-async-getAsyncExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

五、TaskDecorator

       有些情况下,我们需要在主线程和子线程之间传递变量,spring提供了TaskDecorator接口,一般用于日志,用户信息传递。在decorate方法中,对Runnable对象进行包装,可以先行获取主线程中线程本地变量的值,在对子线程进行赋值,注意最后要情况线程本地变量情况,避免内存泄漏。

public class ContextCopyingDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        try {
            Integer data = DataHolder.getData();
            return () -> {
                try {
                    DataHolder.setData(data);
                    runnable.run();
                } finally {
                  DataHolder.removeData();
                }
            };
        } catch (IllegalStateException e) {
            return runnable;
        }
    }
}

public class DataHolder {
    private static final ThreadLocal<Integer> CURRENT_USER_THREAD_LOCAL = new ThreadLocal<>();

    public static void setData(Integer num) {

        CURRENT_USER_THREAD_LOCAL.set(num);
    }

    public static Integer getData() {
        Integer num = CURRENT_USER_THREAD_LOCAL.get();
        if (num == null) {
            return null;
        }
        return num;
    }
    public static void removeData() {
        CURRENT_USER_THREAD_LOCAL.remove();
    }
}

       要在initializeExecutor方法中,新建ThreadPoolExecutor,在有TaskDecorator存在的情况下,回对execute方法进行重写,对任务进行包装。

protected ExecutorService initializeExecutor(
			ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {

		BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);

		ThreadPoolExecutor executor;
		if (this.taskDecorator != null) {
			executor = new ThreadPoolExecutor(
					this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
					queue, threadFactory, rejectedExecutionHandler) {
				@Override //重写execute方法,使用装饰器装饰
				public void execute(Runnable command) {
					super.execute(taskDecorator.decorate(command));
				}
			};
		}
		return executor;
	}

总结

本文主要分析了spring中异步任务的创建和执行流程,并且实现了自定义异步线程池,关于异步任务导致的循环依赖问题将在接下来的文章中分析

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值