Spring源码分析:Async源码分析

一、引入@Async

1、@EnableAsync()

属性:

  1. annotation:该属性用来支持用户自定义异步注解,默认扫描spring的
    @Async和EJB3.1的@code和@javax.ejb.Asynchronous
  2. proxyTargetClass:true或者false 标明是否需要创建CGLIB子类代理,AdviceMode=PROXY时才适用。注意设置为true时,其它spring管理的bean也会升级到CGLIB子类代理
  3. mode :标明异步通知将会如何实现,默认PROXY,如需支持同一个类中非异步方法调用另一个异步方法,需要设置为ASPECTJ 默认:AdviceMode.PROXY
  4. order :标明异步注解bean处理器应该遵循的执行顺序,默认最低的优先级(Integer.MAX_VALUE,值越小优先级越高) 默认:Ordered.LOWEST_PRECEDENCE;

2、@Async()

属性:

value :搜索TaskExecutor类型的bean或者名字为taskExecutor的Executor类型的bean,都不存在使用SimpleAsyncTaskExecutor执行器

3、如何自定义Async所需要的线程池:

实现AsyncConfigurer接口重写getAsyncExecutor获取异步执行器,getAsyncUncaughtExceptionHandler获取异步未捕获异常处理器

@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(7);
        executor.setMaxPoolSize(42);
        executor.setQueueCapacity(11);
        executor.setThreadNamePrefix("MyExecutor-");//线程前缀
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return MyAsyncUncaughtExceptionHandler();//@Async处理失败返回的异常类型
    }
}

4、返回值:

  1. void
  2. Future(AsyncResult或者CompletableFuture)

二、源码分析

先总结一下,因为下面步骤写的太乱了,我自己都看不下去,但又没时间整理。

1、先实例化ProxyAsyncConfiguration这个类,实例化前该类和他的父类有2个方法要先执行,分别是 setConfigurers、asyncAdvisor
2、执行setConfigurers方法,里面要用到AsyncConfigurer的实现类,也就是上面我们定义的AppConfig类,然后拿到AsyncConfigurer实现的2个方法返回值,保存起来(线程池和异常处理类)。
3、在执行AsyncConfigurer方法,该方法会创建AsyncAnnotationBeanPostProcessor对象。
4、在实例化AsyncAnnotationBeanPostProcessor时,会创建AsyncAnnotationAdvisor对象,AsyncAnnotationAdvisor很重要。
5、AsyncAnnotationAdvisor会生成AnnotationAsyncExecutionInterceptor对象。和AnnotationMatchingPointcut对象,这个2个对象分别是切面里面的,通知和切点。
6、先说通知,AnnotationAsyncExecutionInterceptor对象间接实现了MethodInterceptor接口,也就意味着这是一个拦截器,当目标方法被执行前后,执行额外逻辑。看下它实现MethodInterceptor的invoke方法。

@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
    Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
    Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
    AsyncTaskExecutor executor = this.determineAsyncExecutor(userDeclaredMethod);  //拿到执行器
    
    //创建一个任务
	Callable<Object> task = () -> {
        try {
            Object result = invocation.proceed();//执行目标方法,也就是加了@Async注解的方法。
            if (result instanceof Future) {
                return ((Future)result).get();
            }
        } catch (ExecutionException var4) {
            this.handleError(var4.getCause(), userDeclaredMethod, invocation.getArguments());
        } catch (Throwable var5) {
            this.handleError(var5, userDeclaredMethod, invocation.getArguments());
        }
        return null;
    };

    //将任务任务task丢到线程池里面执行
    return this.doSubmit(task, executor, invocation.getMethod().getReturnType());
}

7、再说切点,切点就用到AnnotationMatchingPointcut这个类,这个类很粗暴,只需要指定需要拦截的注解@Async,并且支持拦截类上面的还是方法上面的,这样一个切面就生成好了。
8、接下来就是带有@Async的目标类或者方法开始实例化,在Bean被实例化时,会遍历一遍所有的BeanPostProcessor,这里就包括AsyncAnnotationBeanPostProcessor。
9、AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization方法里面会判断,当前实例化的Bean的类或者方法是否符合切点规则

当符合规则时,就会给这个Bean创建代理对象,并且绑定通知。这里就和切面一个意思了。

1、@EnableAsync注解源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
    //默认是@Async和EJB3.1规范下的@Asynchronous注解,
    //这里表示可以自定义注解启动异步
    Class<? extends Annotation> annotation() default Annotation.class;
    
    boolean proxyTargetClass() default false; //true表示启用CGLIB代理
    
    // 切面通知模式:默认动态代理PROXY
    AdviceMode mode() default AdviceMode.PROXY;
    
    int order() default Ordered.LOWEST_PRECEDENCE;
}

这个EnableAsync注解,一般注解属性我们都不需要改,默认就行了。那么这里最重要的代码就只有一行了,就是这个**@Import(AsyncConfigurationSelector.class)**,导入AsyncConfigurationSelector配置。

2、AsyncConfigurationSelector

//关键点:1、父类AdviceModeImportSelector
//2、导入配置类ProxyAsyncConfiguration
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

    private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME = "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

    public AsyncConfigurationSelector() {
    }

    @Nullable
    public String[] selectImports(AdviceMode adviceMode) {
        switch(adviceMode) {
        case PROXY:
            return new String[]{ProxyAsyncConfiguration.class.getName()};
        case ASPECTJ:
            return new String[]{"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"};
        default:
            return null;
        }
    }
}

上面的源码里面,我在开头写了2个关键点:

  1. 一个是父类AdviceModeImportSelector
  2. 二是导入配置类ProxyAsyncConfiguration

ImportSelector也是spring的一个比较特殊的接口了,我们就从selectImports(AnnotationMetadata)方法看起:

public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {

    public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
    protected String getAdviceModeAttributeName() {
        return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME;
    }

    @Override
    public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
        Class<?> annType = 
                 GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
        
        // 获取@EnableAsync的属性值
        AnnotationAttributes attributes = 
                           AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);

        AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());

        // 调用抽象方法,由子类重写
        String[] imports = selectImports(adviceMode);
        return imports;
    }

    /**
     * 由子类AsyncConfigurationSelector重写了这个方法
     */
    @Nullable
    protected abstract String[] selectImports(AdviceMode adviceMode);
}

所以从这个方法看起你就很容易梳理到代码了。上面代码中,首先把EnableAsync的元数据都封装到AnnotationAttributes中,然后再获取到AdviceMode,最后选择出需要导入的配置,而导入的配置方法是个抽象方法selectImports(AdviceMode),由子类重写。子类自然就是AsyncConfigurationSelector,所以你才可以看到AsyncConfigurationSelector里有个selectImports方法,其实是重写了父类的。

现在逻辑相对清晰了,由于AdviceMode默认就是AdviceMode.PROXY,所以我们导入的配置就是ProxyAsyncConfiguration,接下来我们再去分析。

3、ProxyAsyncConfiguration

这看配置类的名称,翻译过来就是代理异步配置。有时候我们看源码也要从一个类的名称去猜测可能的功能。aop也是使用的了代理。那么应该就是在这个配置类里面实现的了。好了,由一个名字我想了这么多,接下来先看下代码:

/*
 * 这里的关键点有2个:
 * 1、父类AbstractAsyncConfiguration
 * 2、初始化对象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() {
       
        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.<Integer>getNumber("order"));
        return bpp;
    }
}

上面我依然点出了两个重点:

  1. 父类AbstractAsyncConfiguration
  2. 初始化对象AsyncAnnotationBeanPostProcessor

为什么一直强调父类,因为子类初始化之前,父类是要先完成初始化的,所以加载顺序都是父类先加载,这点必须清楚,另外就是子类一般都要重写父类的方法,重写的方法一般在父类的其他方法中会被调用

既然是继承关系,我们依然来看下继承关系图: 上面我们就看到了Aware系列的接口之一ImportAware,作用是通过实现ImportAware接口获取对应注解的元数据。
所以,我们先去看完父类AbstractAsyncConfiguration,然后再回头来看子类ProxyAsyncConfiguration。

4、AbstractAsyncConfiguration

@Configuration
public abstract class AbstractAsyncConfiguration implements ImportAware {
    @Nullable
    protected AnnotationAttributes enableAsync;//注解里面的所有属性
    @Nullable
    protected Supplier<Executor> executor;//执行器
    @Nullable
    protected Supplier<AsyncUncaughtExceptionHandler> exceptionHandler;//异步执行异常的处理器

    /**
     * 通过实现ImportAware接口获取@EnableAsync的属性值
     */
    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        this.enableAsync = 
                  AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
    }

    /**
     * 导入自定义的实现了AsyncConfigurer接口的bean 并给executor、exceptionHandler附上自定义的值
     */
    @Autowired(required = false)
    void setConfigurers(Collection<AsyncConfigurer> configurers) {
        // 如果没有自定义实现AsyncConfigurer接口,直接返回
        if (CollectionUtils.isEmpty(configurers)) {
            return;
        }
        if (configurers.size() > 1) {
            throw new IllegalStateException("Only one AsyncConfigurer may exist");
        }

        // 有的话,直接赋值
        AsyncConfigurer configurer = configurers.iterator().next();
        this.executor = configurer::getAsyncExecutor;
        this.exceptionHandler = configurer::getAsyncUncaughtExceptionHandler;
    }
}
  1. setImportMetadata方法里读取了EnableAsync的元数据存在了AnnotationAttributes 中。
  2. setConfigurers导入自定义的AsyncConfigurer配置类。

文章开始就自定义了线程池和异步线程错误处理器等,就是通过实现AsyncConfigurer接口实现的,而我们自定义的类就会被注入到setConfigurers这个方法中,然后被赋值给当前类的executor和exceptionHandler。

所以这个父类中,其实就是一些初始化,初始化this.enableAsync、this.executor和this.exceptionHandler。 当然了,我们不是必须要实现AsyncConfigurer重写executor和exceptionHandler,所以this.executor和this.exceptionHandler可能还是为null的。

我们再回到ProxyAsyncConfiguration的asyncAdvisor()方法

public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
    
    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((Integer)this.enableAsync.getNumber("order"));
    return bpp;
}

看这个方法名称,有点异步切面的意思呀,那么返回值AsyncAnnotationBeanPostProcessor是否就是一个切面增强类呢?

这个我们去看下继承关系。

在这里插入图片描述

继承的东西比较多,先来说说我们比较熟悉的东西:

  1. BeanClassLoaderAware - 获取当前类的类加载器
  2. BeanFactoryAware - 获取Spring的核心容器BeanFactory
  3. BeanPostProcessor - bean初始化过程中的前置、后置处理器
  4. AbstractAdvisingBeanPostProcessor - 生成aop代理的后置处理器

那么现在来梳理一下逻辑:
首先ProxyAsyncConfiguration中会开始初始化AsyncAnnotationBeanPostProcessor,因为是@Bean,所以在对象注入spring容器之前,你先不用看aware系列,不用看BeanPostProcessor,先看@Bean里面方法的内容,那是注入spring容器之前可能做一些初始化。

而asyncAdvisor()方法中,关键的代码其实也没多少,逻辑如下:

  1. 就是new一个AsyncAnnotationBeanPostProcessor对象
  2. bpp.configure(this.executor, this.exceptionHandler);就是赋值excutor和exceptionHandler

既然上面初始化了AsyncAnnotationBeanPostProcessor我们在看看用了AsyncAnnotationBeanPostProcessor哪些方法

new AsyncAnnotationBeanPostProcessor();

第一个方法

bpp.configure(this.executor, this.exceptionHandler);
public void configure(@Nullable Supplier<Executor> executor, 
                      @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
    this.executor = executor;
    this.exceptionHandler = exceptionHandler;
}

第二个代码

bpp.setAsyncAnnotationType(customAsyncAnnotation);
public void setAsyncAnnotationType(Class<? extends Annotation> asyncAnnotationType) {
    this.asyncAnnotationType = asyncAnnotationType;
}

接下来就是重点之中的重点了,可以说@Async的重点核心就是AsyncAnnotationBeanPostProcessor这个类,之前做了这么多准备就是为了初始化这个类。
我们来看一下文章开始的内容,先获取自定义了的excutor和exceptionHandler,然后新建了AsyncAnnotationBeanPostProcessor对象并注入到了spring容器中,因为bean的生命周期比较复杂。
我怕很多人没研究过spring的容器,对spring bean的声明周期不太了解,特意从网上找了一张总结的图,让大家一张图搞懂Spring bean的生命周期,从Spring容器启动到容器销毁bean的全过程。

在这里插入图片描述

通过这个图,我们再回到我们的这个AsyncAnnotationBeanPostProcessor这个类的继承关系图,你就知道了执行的顺序流程如下:

  1. 因为实现了BeanPostProcessor,所以先执行postProcessBeforeInitialization
  2. 执行构造器方法
  3. 执行BeanFactoryAware 、BeanClassLoaderAware的对应方法
  4. 执行BeanPostProcessor的postProcessAfterInitialization方法

ok,顺序已给出,那么初始化的过程就清晰了,接下来我们只需要一步一步去看对应模块的代码。

5、AsyncAnnotationBeanPostProcessor

5.1 第一步:postProcessBeforeInitialization

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
    return bean;//好像啥都没做,忽略
}

5.2 第二步:构造器

其实对象我们是new出来的,然后再通过@Bean注入容器的,并不是使用@Component或者xml方式注入,所以构造器应该是早就执行了

public AsyncAnnotationBeanPostProcessor() {
    setBeforeExistingAdvisors(true);
}

这个构造器只有一行代码,是说是不是在其他已存在的aop之前执行,参数表示是的。

5.3 第三步:BeanClassLoaderAware、BeanFactoryAware

因为BeanClassLoaderAware是aop代码部分的了,是为了给对象生成代理的时候统一类加载器。所以这个方法我们不需要看。我们来看下BeanFactoryAware的setBeanFactory方法:

AsyncAnnotationBeanPostProcessor#setBeanFactory

@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;
}

代码中,除了引入beanFactory之外,还定义了一个切面advisor ,并把切面advisor赋值给当前对象。

编码实现一个aop,需要准备几个东西,可以看这里:手写AOP

  1. ProxyFactory 代理工厂
  2. Pointcut 切点
  3. Advice 通知
  4. Advisor 切面
  5. Target 被代理对象

有了这几个组件之后,我们就可以构建成一个aop。

那么再看这里代码,这里的advisor就在这里初始化获取到了。而我们可以这样理解:Advisor = pointcut + Advice ,所以可说,我们完成了切面的初始化,其实也是@Async核心重要的一部分了。

ok,有了知识储备,搞啥都清晰。我们接着往下面走, 看AsyncAnnotationAdvisor的初始化过程先,也就是构造方法:


new AsyncAnnotationAdvisor(this.executor,this.exceptionHandler);//创建切面

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);//通知
    this.pointcut = buildPointcut(asyncAnnotationTypes);  //切点
}

protected Advice buildAdvice(@Nullable Supplier<Executor> executor, 
                            @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
    AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
    interceptor.configure(executor, exceptionHandler);
    return interceptor;//得到通知,这个通知父类有个invoke方法,类似环绕通知
}
protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
    ComposablePointcut result = null;
    for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
        Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
        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);
}

上面重点是这两行:

  1. this.advice = buildAdvice(executor, exceptionHandler);//通知
  2. this.pointcut = buildPointcut(asyncAnnotationTypes);//切点

切面等于切点加通知处理。就是这两样东西了。也就是构造器里面其实得到了切点和通知。

我们先来看下通知AnnotationAsyncExecutionInterceptor的继承关系:

在这里插入图片描述

这里面我们比较熟悉的类有Advice、Interceptor、BeanFactoryAware。AnnotationAsyncExecutionInterceptor类就是我们环绕通知的处理类了,Advice说明了这个类是个aop通知处理类,Interceptor说明了处理的方法是拦截器的invoke方法。切面拦截到切点时候就会到这个方法的invoke中执行对应的业务处理逻辑。那么对应到@Async,执行的逻辑应该就是起一个线程执行方法。清楚了这一点之后,我们再回到AnnotationAsyncExecutionInterceptor构造方法中,最终调用的是父类中的构造方法:

new AnnotationAsyncExecutionInterceptor(null);

public AnnotationAsyncExecutionInterceptor(@Nullable Executor defaultExecutor) {
    super(defaultExecutor);
}

public AsyncExecutionAspectSupport(@Nullable Executor defaultExecutor) {
    this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () ->getDefaultExecutor(this.beanFactory));

    this.exceptionHandler = SingletonSupplier.of(SimpleAsyncUncaughtExceptionHandler::new);
}

这里就是给executor和exceptionHandler一个初始化的执行器或错误处理器,初始化默认处理器之后再执行interceptor.configure(executor, exceptionHandler);所以就是我们不创建处理器,spring也会给他默认的

interceptor.configure(executor, exceptionHandler);

public void configure(@Nullable Supplier<Executor> defaultExecutor,
                      @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

    this.defaultExecutor = new SingletonSupplier<>(defaultExecutor, () -> getDefaultExecutor(this.beanFactory));
    this.exceptionHandler = new SingletonSupplier<>(exceptionHandler,SimpleAsyncUncaughtExceptionHandler::new);
}

这意思就是如果我们之前自定义了执行器和错误处理器,那么用我们自定义的,如果没有就用刚刚在构造器中初始化的默认的。所以,切面的环绕通知处理Advice已经生成。我们再来看看另一个方法

AsyncAnnotationAdvisor#buildPointcut 生成切入点

protected Pointcut buildPointcut(Set<Class<? extends Annotation>> asyncAnnotationTypes) {
    ComposablePointcut result = null;
    for (Class<? extends Annotation> asyncAnnotationType : asyncAnnotationTypes) {
        Pointcut cpc = new AnnotationMatchingPointcut(asyncAnnotationType, true);
        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);
}

这生成切点的逻辑也挺简单的,之前允许在@EnableAsync中通过annatation定义自定义的异步线程注解,我们常用的默认是@Async。所以这里意思其实是把所有的可能的注解都union起来,union就是合并意思。不管自定义的,还是默认的都作为切点。

这时候切点Pointcut已初始化好。
所以在AsyncAnnotationAdvisor中我们初始化好了Advice和Pointcut,而切面就等于Advice+Pointcut,那么它是一个切面来的吗?我们来看下继承关系:

在这里插入图片描述

AsyncAnnotationAdvisor实现了Advisor,是个切面。所以致此,我们已经定义了一个切面。

5.4 第四步:执行BeanPostProcessor的postProcessAfterInitialization方法

上面三步走完之后,我们定义得到了一个切面,接下来我们进入最后一步,就是bean的后置处理,这个后置处理器其实是aop中实现的,所以我们定义一个aop切面,其实都需要进入这个后置处理器,那么这里面做了什么事情呢?

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
    if (this.advisor == null || bean instanceof AopInfrastructureBean) {
        return bean;
    }

    if (bean instanceof Advised) {
        Advised advised = (Advised) bean;
        if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
            if (this.beforeExistingAdvisors) {
                advised.addAdvisor(0, this.advisor);
            } else {
                advised.addAdvisor(this.advisor);
            }
            return bean;
        }
    }

    if (isEligible(bean, beanName)) {
        //创建代理
        ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
        if (!proxyFactory.isProxyTargetClass()) {
            evaluateProxyInterfaces(bean.getClass(), proxyFactory);
        }

        proxyFactory.addAdvisor(this.advisor);//设置切点
        customizeProxyFactory(proxyFactory);
        return proxyFactory.getProxy(getProxyClassLoader());
    }
    return bean;
}

protected void customizeProxyFactory(ProxyFactory proxyFactory) {
}

看了里面的逻辑,就是直接给bean生成代理的了

prepareProxyFactory(bean, beanName);

protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {
    ProxyFactory proxyFactory = new ProxyFactory();

    proxyFactory.copyFrom(this);
    proxyFactory.setTarget(bean);

    return proxyFactory;
}

6、AnnotationAsyncExecutionInterceptor

前面buildAdvice()方法我们定义了

protected Advice buildAdvice(@Nullable Supplier<Executor> executor, 
                            @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
    AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
    interceptor.configure(executor, exceptionHandler);
    return interceptor;//得到通知
}

接下来我们回头来看环绕通知处理里面的业务逻辑,因为现在aop已经生成,拦截@Async之后我们需要异步处理代理的方法。这时候我们进入AnnotationAsyncExecutionInterceptor的invoke方法。

在父类中AsyncExecutionInterceptor#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);

    // 获取executor执行器
    AsyncTaskExecutor executor = determineAsyncExecutor(userDeclaredMethod);

    // 定义一个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());
}

protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
    if (CompletableFuture.class.isAssignableFrom(returnType)) {
        
        return CompletableFuture.supplyAsync(() -> {
            try {
                return task.call();
            } catch (Throwable ex) {
                throw new CompletionException(ex);
            }
        }, executor);
        
    } else if (ListenableFuture.class.isAssignableFrom(returnType)) {
        
        return ((AsyncListenableTaskExecutor) executor).submitListenable(task);
        
    } else if (Future.class.isAssignableFrom(returnType)) {
        
        return executor.submit(task);
        
    } else {
        executor.submit(task);
        return null;
    }
}

上面第一步获取到executor,然后再通过Callable定义一个异步线程。然后把task放在doSubmit中执行。

三、总结

上面所有的内容,我们再来梳理一下proxyFactory的伪代码过程:

public static void main(String[] args) {
	ProxyFactory proxyFactory = new ProxyFactory();

    // 目标代理类
    proxyFactory.setTarget("UserServiceImpl bean");

    // 代理接口
    proxyFactory.addInterface("UserService");

    // 切点
    AsyncAnnotationAdvisor.pointcut = @Async注解修饰的地方;
    
    //环绕通知处理
    AsyncAnnotationAdvisor.advice = AnnotationAsyncExecutionInterceptor;

    // 切面 = 切点+通知
    proxyFactory.addAdvisor("AsyncAnnotationAdvisor");

    // 生成代理
    UserService userService = proxyFactory.getProxy(getProxyClassLoader());
}

注意

加了@Async注解的方法,是不能随意使用返回值比如源码有这一段判断

针对返回值判断是否是Future的类型,如果不是则返回null,返回null是没有问题,问题在于下面这种图
返回值retVal是null,并且returnType不是void,而且还是基本类型,也就是八大基础类型,那么就会报错,所以这里使用要小心,哪怕返回值是一个包装类型都可以。

本文摘自:https://blog.csdn.net/weweeeeeeee/article/details/101597540

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信仰_273993243

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值