尝试自定义注解替代 @Async注解

102 阅读3分钟

为什么@Async注解会存在循环问题?

参考:https://juejin.cn/post/6844904048001286158

参考:https://cloud.tencent.com/developer/article/1497689

从中可知@Async产生循环依赖的原因: 对于AOP解决循环依赖的思路是: AnnotationAwareAspectJAutoProxyCreator是AOP处理类,实现了SmartInstantiationAwareBeanPostProcessor接口,利用getEarlyBeanReference可以实现AOP代理对象,后置处理postProcessAfterInitialization方法中发现这个对象已经进行过代理,因此就不再处理。

@Async 处理类AsyncAnnotationBeanPostProcessor,没有实现SmartInstantiationAwareBeanPostProcessor接口,它对循环依赖的处理并不像AnnotationAwareAspectJAutoProxyCreator一样,放到三级缓存的 ObjectFactory对象可以利用getEarlyBeanReference可以识别AOP并且产生代理对象,@Async只有在postProcessAfterInitialization方法中产生代理;如下图代码,生成A bean对象,按照bean的生命周期

  1. 先实例化A对象ObjectFactoryA放到三级缓存中
  2. A开始对象开始对属性B赋值,B先实例化,然后对属性A赋值,先从三级缓存ObjectFactoryA开始执行 getEarlyBeanReference方法,由于没有实现SmartInstantiationAwareBeanPostProcessor接 口,获取的是原始的对象A;
  3. 后面A继续初始化,会执行AsyncAnnotationBeanPostProcessor的 postProcessAfterInitialization方法,最终得到是一个代理对象proxyA,和2中的对象A不是同一 个对象
@Service public class A implements AInterface {
@Autowired 
private BInterface b; 
@Async 
@Override 
public void funA() { 
 } 
} 
@Service public class B implements BInterface { 
@Autowired private AInterface a; 
@Override 
public void funB() { 
a.funA();
} 

}

@Async是否能和AOP一样解决循环依赖问题

查看@Transactional的处理是通过TransactionInterceptor的invoke方法处理的,前提是先设置Advice的拦截器,

image.png

@Async 是否也可以这样处理?我尝试自定义注解实现下

定义注解@AsyncT

@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AsyncT {

    String value() default "";
}

写一个方法增强拦截器,参考spring的AsyncExecutionInterceptor实现 `

@Slf4j
@Component
public class AsyncTInterceptor  implements MethodInterceptor, Ordered, BeanFactoryAware {

    @Nullable
    private BeanFactory beanFactory;

    private final Map<Method, AsyncTaskExecutor> executors = new ConcurrentHashMap<>(16);

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }


    @Override
    public Object invoke(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 = () -> {
            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 void handleError(Throwable ex, Method method, Object... params) throws Exception {
        log.error(" AsyncTInterceptor handleError execute failed:{}", ex);
        if (Future.class.isAssignableFrom(method.getReturnType())) {
            ReflectionUtils.rethrowException(ex);
        }
    }
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
    @Nullable
    protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
        AsyncTaskExecutor executor = this.executors.get(method);
        if (executor == null) {
            Executor targetExecutor;
            String qualifier = getExecutorQualifier(method);
            if (StringUtils.hasLength(qualifier)) {
                targetExecutor = findQualifiedExecutor(this.beanFactory, qualifier);
            }
            else {
                //没有默认值
                targetExecutor = null;
            }
            if (targetExecutor == null) {
                return null;
            }
            executor = (targetExecutor instanceof AsyncListenableTaskExecutor ?
                    (AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));
            this.executors.put(method, executor);
        }
        return executor;
    }

    @Nullable
    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;
        }
    }
    
    @Nullable
    protected String getExecutorQualifier(Method method) {
        // Maintainer's note: changes made here should also be made in
        // AnnotationAsyncExecutionAspect#getExecutorQualifier
        Async async = AnnotatedElementUtils.findMergedAnnotation(method, Async.class);
        if (async == null) {
            async = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Async.class);
        }
        return (async != null ? async.value() : null);
    }
    @Nullable
    protected Executor findQualifiedExecutor(@Nullable BeanFactory beanFactory, String qualifier) {
        if (beanFactory == null) {
            throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
                    " to access qualified executor '" + qualifier + "'");
        }
        return BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, Executor.class, qualifier);
    }
}

`

加入拦截器

@Configuration
public class InterceptorConfig {
       
    public static final String traceExecution = "@annotation(xx.annotation.AsyncT)";//自己包路径

    @Resource
    private AsyncTInterceptor asyncTaskInterceptor;

    @Bean
    public DefaultPointcutAdvisor asyncTaskAdvisor() {
        DefaultPointcutAdvisor asyncTaskAdvisor = new DefaultPointcutAdvisor()
        asyncTaskAdvisor.setPointcut(getPointcut());
        asyncTaskAdvisor.setAdvice(asyncTaskInterceptor);
        return asyncTaskAdvisor;
    }

    private Pointcut getPointcut() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(traceExecution);
        return pointcut;
    }
}

测试是可以成功的,这里就不贴测试代码了,偷懒,在项目中是可以运行的,自己动手多dubug就行