Spring源码之Async注解

Spring源码之Async注解spring@Async注解的处理

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

@EnableAsync注解

	/** * 可自定义扫描的注解 */
	Class<? extends Annotation> annotation() default Annotation.class;

	/** * 采用代理的方式,如果设置为true,后续会使用CGLIB进行代理 */
	boolean proxyTargetClass() default false;

	/** * 使用代理的模式 */
	AdviceMode mode() default AdviceMode.PROXY;

	/** * 注解处理的顺序 */
	int order() default Ordered.LOWEST_PRECEDENCE;

ProxyAsyncConfiguration

	@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public AsyncAnnotationBeanPostProcessor asyncAdvisor() { 
   
	    //创建一个异步注解处理器
		AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
        //将从容器中获取到的 Executor 和 ExceptionHandler设置到对象中
		bpp.configure(this.executor, this.exceptionHandler);
		Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
		if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) { 
   
            //设置自定义的 异步注解
			bpp.setAsyncAnnotationType(customAsyncAnnotation);
		}
        //设置代理方式
		bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
        //设置加载顺序
		bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
		return bpp;
	}

	/** * 获取到注解是否开启异步代理 */
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) { 
   
		this.enableAsync = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableAsync.class.getName()));
		if (this.enableAsync == null) { 
   
			throw new IllegalArgumentException(
					"@EnableAsync is not present on importing class " + importMetadata.getClassName());
		}
	}

	/** * 从容器中找到实现了 AsyncConfigurer 类,然后获取到自定义的 线程执行器和异常处理器;默认为null */
	@Autowired
	void setConfigurers(ObjectProvider<AsyncConfigurer> configurers) { 
   
		//默认会使用第一个配置对象
		Supplier<AsyncConfigurer> configurer = SingletonSupplier.of(() -> { 
   
			List<AsyncConfigurer> candidates = configurers.stream().collect(Collectors.toList());
			if (CollectionUtils.isEmpty(candidates)) { 
   
				return null;
			}
			if (candidates.size() > 1) { 
   
				throw new IllegalStateException("Only one AsyncConfigurer may exist");
			}
			return candidates.get(0);
		});
		this.executor = adapt(configurer, AsyncConfigurer::getAsyncExecutor);
		this.exceptionHandler = adapt(configurer, AsyncConfigurer::getAsyncUncaughtExceptionHandler);
	}
	
	//这里会返回一个Supplier对象用于在 AsyncExecutionAspectSupport 当中设置默认的线程池
	private <T> Supplier<T> adapt(Supplier<AsyncConfigurer> supplier, Function<AsyncConfigurer, T> provider) { 
   
		return () -> { 
   
            //如果不配置 AsyncConfigurer 这里就会返回null
			AsyncConfigurer configurer = supplier.get();
			return (configurer != null ? provider.apply(configurer) : null);
		};
	}

AsyncAnnotationBeanPostProcessor

在这里插入图片描述

1. setBeanFactory()

实现了 BeanFactoryAware 接口,初始化 AsyncAnnotationBeanPostProcessor 时会调用内部的**setBeanFactory() **方法设置切面

在这里插入图片描述

2. postProcessAfterInitialization

方法在容器创建好之后执行,给bean对象创建一个代理对象

AsyncAnnotationAdvisor

	public AsyncAnnotationAdvisor(
			@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) { 
   

		Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
        //添加注解的类型
		asyncAnnotationTypes.add(Async.class);
		try { 
   
			asyncAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) { 
   
			
		}
        //构建一个通知对象
		this.advice = buildAdvice(executor, exceptionHandler);
        //根据注解构造一个切点,切点用于对类进行匹配,匹配了之后真正执行的是 Advice 来进行
        //返回一个ComposablePointcut支持多个过滤方式进行匹配,就是将多个ClassFilter和MethodMather进行合并
		this.pointcut = buildPointcut(asyncAnnotationTypes);
	}

AnnotationAsyncExecutionInterceptor

在这里插入图片描述

	/** * 通过父类的构造器,设置一个默认的线程池的获取方式 */
	public AsyncExecutionAspectSupport(@Nullable Executor defaultExecutor, AsyncUncaughtExceptionHandler exceptionHandler) { 
   
        // defaultExecutor就是在 ProxyAsyncConfiguration 中设置的Supplier对象,如果获取不到就调用
		this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory));
		this.exceptionHandler = SingletonSupplier.of(exceptionHandler);
	}

1. getExecutorQualifier()

protected String getExecutorQualifier(Method method) { 
   
    //获取到方法上面的注解,获取到vlue值,然后通过value值去确定线程池
		Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
		if (async == null) { 
   
			async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
		}
		return (async != null ? async.value() : null);
	}

2. invoke()

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);
    //确定异步使用的线程池 默认使用 SimpleAsyncTaskExecutor
		AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);
		if (executor == null) { 
   
			throw new IllegalStateException();
		}
		//包装成 Callable 类的任务
		Callable<Object> task = () -> { 
   
			try { 
   
				Object result = invocation.proceed();
				if (result instanceof Future) { 
   
					return ((Future<?>) result).get();
				}
			}
			catch (ExecutionException ex) { 
   
				handleError(ex.getCause(), userDeclaredMethod, invocation.getArguments());
			}
			catch (Throwable ex) { 
   
				handleError(ex, userDeclaredMethod, invocation.getArguments());
			}
			return null;
		};
		//提交方法执行
		return doSubmit(task, executor, invocation.getMethod().getReturnType());
	}

3. determineAsyncExecutor()

protected AsyncTaskExecutor determineAsyncExecutor(Method method) { 
   
    //初始获取的会是null
		AsyncTaskExecutor executor = this.executors.get(method);
		if (executor == null) { 
   
			Executor targetExecutor;
            //调用复写的方法通过注解来获取到对应的value来确定容器中的线程池名称
			String qualifier = getExecutorQualifier(method);
			if (StringUtils.hasLength(qualifier)) { 
   
				targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
			}
			else { 
   
                //调用默认的 SingletonSupplier 对象来获取到对应的默认线程池。如果设置的对象都没有获取到,就会调用 getDefaultExecutor() 方法
				targetExecutor = this.defaultExecutor.get();
			}
			if (targetExecutor == null) { 
   
				return null;
			}
			executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
					(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
            //缓存上
			this.executors.put(method, executor);
		}
		return executor;
	}

4. getDefaultExecutor()

AsyncExecutionInterceptor复写的方法,如果都容器中都没有获取到对应的线程池,那么就返回 SimpleAsyncTaskExecutor

	protected Executor getDefaultExecutor(@Nullable BeanFactory beanFactory) { 
   
        //调用父类方法去获取线程池
		Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
		return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
	}

面试题

spring中Async注解是使用线程池进行异步处理,还是使用单线程?
答:根据spring容器中配置的 ObjectProvider<AsyncConfigurer> configurers 配置对象进行配置线程池还是单线程进行异步处理;如果没有指定配置对象那么默认就会去容器中查找 TaskExecutor 类型如果抛出异常就会去找名称为 taskExecutor 类型为 Executor 的线程池;如果都没有则使用默认 SimpleAsyncTaskExecutor 单线程进行异步处理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157804.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【手把手】制作一个简单的HTML网页

    【手把手】制作一个简单的HTML网页新建一个html文件:我要给body添加一些样式,就在head元素上挂载一个style元素。然后,写样式表:效果:这样的话,我们就可以看到body部分了。现在,我给body添加一点padding。页面上看不出区别,让我们打开F12,看一下现在的body变成了什么样子。示意图:从图中可以看出,body元素分为三层,最里面的一层,就是520×500的那部分,这个叫做内部真实空间,也就是说,你可以在里面添加其他元素,比如div元素,p元素,a元素等等。然后中间的一层就是paddin

    2022年7月27日
    16
  • leetcode-33搜索旋转排序数组(二分)[通俗易懂]

    leetcode-33搜索旋转排序数组(二分)[通俗易懂]整数数组 nums 按升序排列,数组中的值 互不相同 。在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。给你 旋转后 的数组 nums 和一个整数 ta

    2022年8月8日
    4
  • C++中string append函数的使用与字符串拼接「建议收藏」

    C++中string append函数的使用与字符串拼接「建议收藏」常用的函数原型:basic_string&amp;amp;amp;append(constbasic_string&amp;amp;amp;str);basic_string&amp;amp;amp;append(constchar*str);basic_string&amp;amp;amp;append(constbasic_string&amp;amp;amp;str,size_typeindex,size

    2022年6月24日
    26
  • Python之高级库socketserver

    socket并不能多并发,只能支持一个用户,socketserver简化了编写网络服务程序的任务,socketserver是socket的在封装。socketserver在python2中为Sock

    2021年12月18日
    42
  • sql学生选课管理系统[通俗易懂]

    sql学生选课管理系统[通俗易懂]一、概要设计1.1目的和意义学生选课系统作为一种现代化的教学技术,被广泛应用于学校的学生选课,是一个学校不可或缺的部分,学生选课系统使管理选课信息更加简单,学生选课更加方便。学生选课系统的将使选课管理工作规范化、系统化、程序化,避免选课管理的无条理性,提高信息处理的速度和准确性,能够准确、及时、有效的查询和修改学生选课情况。与传统的选课方式相比,网上选课系统利用局域网为学生选课带来了极大的便捷。学生在公共机房,或者宿舍的个人电脑上便可以通过校园网络来选课。在选课时间内,学生能够使用选课系统灵活的修

    2022年10月9日
    0
  • Java的泛型

    Java的泛型使用Java的小伙伴,对于Java的一些高级特性一定再熟悉不过了,例如集合、反射、泛型、注解等等,这些可以说我们在平时开发中是经常使用到的,尤其是集合,基本是只要写代码没有用不到的,今天我…

    2022年7月7日
    21

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号