我的心血全在这了,这种方式讲@Async原理,你别再不懂Spring了

@EnableAsync

public class SpringBootAsyncApplication {

public static void main(String[] args) {

SpringApplication.run(SpringBootAsyncApplication.class, args);

}

}

既然通过@EnableAsync注解可以开启异步功能,那么该注解就是我们探秘的入口

进入@EnableAsync注解,就会看到另一个熟悉的注解@Import,该注解的功能就是在程序中引入相关功能对应的配置类

@Import(AsyncConfigurationSelector.class)

public @interface EnableAsync {}

点开AsyncConfigurationSelector,可以看到此次引入的是ProxyAsyncConfiguration配置类

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配置类

@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();

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.getNumber(“order”));

return bpp;

}

可以看到ProxyAsyncConfiguration配置类中声明AsyncAnnotationBeanPostProcessor这样一个Bean,从字面意思也可以猜出该Bean应该就是异步处理的主角,接下来就来看看这个主角做了哪些工作

进入AsyncAnnotationBeanPostProcessor中,可以看到该类实现了BeanFactoryAware、BeanPostProcessor这两个与Bean生命周期息息相关的接口,由Bean的生命周期特性可以得知BeanFactoryAware接口的实现方法先于BeanPostProcessor接口的实现方法执行。

2.1.2 BeanFactoryAware实现

2.1.2.1 定义切面

@Override

public void setBeanFactory(BeanFactory beanFactory) {

super.setBeanFactory(beanFactory);

// 定义切面

AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);

if (this.asyncAnnotationType != null) {

advisor.setAsyncAnnotationType(this.asyncAnnotationType);

}

advisor.setBeanFactory(beanFactory);

this.advisor = advisor;

}

在setBeanFactory()实现方法中定义了切面对象,看到切面这两个字,相信你的脑海中会立马浮现出与之有关的两个概念:切点、通知

  • 切点:用来声明切入的目标

  • 通知:针对切入目标的相应处理

2.1.3 定义切点

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) {

// If EJB 3.1 API not present, simply ignore.

}

protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {

ComposablePointcut result = null;

for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {

// 定义在类上标注@Async、@Asynchronous注解的切点

Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);

// 定义在方法上标注@Async、@Asynchronous注解的切点

Pointcut mpc = new AnnotationMatchingPointcut(null, asyncAnnotationType, true);

if (result == null) {

result = new ComposablePointcut(cpc);

}

else {

result.union(cpc);

}

result = result.union(mpc);

}

return (result != null ? result : Pointcut.TRUE);

}

2.1.4 定义通知

protected Advice buildAdvice(

@Nullable Supplier executor, @Nullable Supplier exceptionHandler) {

// 定义通知

AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);

interceptor.configure(executor, exceptionHandler);

return interceptor;

}

通知就是最终要执行的,也是相当重要的一部分,既然很重要,那就需要我们来看看具体的实现

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对象

Callable task = () -> {

try {

Object result = invocation.proceed();

if (result instanceof Future) {

return ((Future<?>) result).get();

}

}

return null;

};

return doSubmit(task, executor, invocation.getMethod().getReturnType());

}

protected Object doSubmit(Callable task, AsyncTaskExecutor executor, Class<?> returnType) {

// 异步任务的返回值类型是CompletableFuture

if (CompletableFuture.class.isAssignableFrom(returnType)) {

return CompletableFuture.supplyAsync(() -> {

try {

return task.call();

}

catch (Throwable ex) {

throw new CompletionException(ex);

}

}, executor);

}

// 异步任务的返回值类型是ListenableFuture

else 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;

}

}

通知的具体实现如下:

  • 第一步获取异步任务线程池,用来执行异步任务

  • 使用Callable包裹目标方法

  • 执行异步异步任务,根据不同的返回值类型做相应的处理

通过通知可以了解到异步任务最终实现的原理,你可能还有疑问,那就是如何告知通知来执行异步任务呢?

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

机会是留给有准备的人,大家在求职之前应该要明确自己的态度,熟悉求职流程,做好充分的准备,把一些可预见的事情做好。

对于应届毕业生来说,校招更适合你们,因为绝大部分都不会有工作经验,企业也不会有工作经验的需求。同时,你也不需要伪造高大上的实战经验,以此让自己的简历能够脱颖而出,反倒会让面试官有所怀疑。

你在大学时期应该明确自己的发展方向,如果你在大一就确定你以后想成为Java工程师,那就不要花太多的时间去学习其他的技术语言,高数之类的,不如好好想着如何夯实Java基础。下图涵盖了应届生乃至转行过来的小白要学习的Java内容:

请转发本文支持一下

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
绝大部分都不会有工作经验,企业也不会有工作经验的需求。同时,你也不需要伪造高大上的实战经验,以此让自己的简历能够脱颖而出,反倒会让面试官有所怀疑。

你在大学时期应该明确自己的发展方向,如果你在大一就确定你以后想成为Java工程师,那就不要花太多的时间去学习其他的技术语言,高数之类的,不如好好想着如何夯实Java基础。下图涵盖了应届生乃至转行过来的小白要学习的Java内容:

请转发本文支持一下

[外链图片转存中…(img-VcKG73pm-1713692722270)]

[外链图片转存中…(img-ozodGk80-1713692722270)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值