zoukankan      html  css  js  c++  java
  • Spring 源码学习

    本文作者:geek,一个聪明好学的朋友

    1. 简介

    开发中我们需要异步执行某个耗时任务时候需要@Async,以下我将从源码角度解释该注解的实现原理。

    2.前提条件@EnableAsync

    ​ 项目使用中,需要添加@EnableAsync注解支持,才能使用@Async(也支持自定义注解)生效。@EnableAsync(默认mode为AdviceMode.PROXY情况下)作用为了给spring项目加入AsyncConfigurationSelector,从而引入AsyncAnnotationBeanPostProcessor。

    @Import(AsyncConfigurationSelector.class)
    public @interface EnableAsync {}
    
    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");
    		/**
    		 *  创建postProcessor,支持定制executor与exceptionHandler
    		 */
        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;
    	}
    
    }
    

    3.AsyncAnnotationBeanPostProcessor的作用

    AsyncAnnotationBeanPostProcessor为加了@Async注解的方法的目标类加入AsyncAnnotationAdvisor。AsyncAnnotationAdvisor也即是spring AOP中责任链调用的advisor,可见被@Async的实现是通过生成代理对象来实现的。
    
    public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
    
    	@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;
    	}
    
    }
    
    public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
    public AsyncAnnotationAdvisor(
    			@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
    
      /**
      *  支持Async与Asynchronous
      */
    		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.
    		}
    		this.advice = buildAdvice(executor, exceptionHandler);
    		this.pointcut = buildPointcut(asyncAnnotationTypes);
    	}
      
      /**
    	 * // 这个最终又是委托给`AnnotationAsyncExecutionInterceptor`,它是一个具体的增强器,有着核心内容
    	 * @param executor
    	 * @param exceptionHandler
    	 * @return
    	 */
    	protected Advice buildAdvice(
    			@Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {
    
    		AnnotationAsyncExecutionInterceptor interceptor = new AnnotationAsyncExecutionInterceptor(null);
    		interceptor.configure(executor, exceptionHandler);
    		return interceptor;
    	}
     }
    

    4.AnnotationAsyncExecutionInterceptor核心内容

    ​ AnnotationAsyncExecutionInterceptor继承AsyncExecutionInterceptor间接实现了MethodInterceptor,该拦截器的实现的invoke方法把原来方法的调用提交到新的线程池执行,从而实现了方法的异步。当需要获得异步结果时,支持CompletableFuture,ListenableFuture,Future的返回。

    public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport implements MethodInterceptor, Ordered {@Override
    	@Nullable
    	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");
    		}
        /**
        *  构建放到AsyncTaskExecutor执行Callable Task
        */
    		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());
    	}
    }
    

    5. 使用注意事项

    5.1使用@Aysnc的时候最好配置一个线程池Executor以让线程复用节省资源,或者为SimpleAsyncTaskExecutor设置基于线程池实现的ThreadFactory,在否则会默认使用SimpleAsyncTaskExecutor,该executor会在每次调用时新建一个线程。

    /**
    * SimpleAsyncTaskExecutor继承自CustomizableThreadCreator,可以看到线程直接new
    */
    public class CustomizableThreadCreator implements Serializable {	
    public Thread createThread(Runnable runnable) {
    		Thread thread = new Thread(getThreadGroup(), runnable, nextThreadName());
    		thread.setPriority(getThreadPriority());
    		thread.setDaemon(isDaemon());
    		return thread;
    	}
    }
    

    5.2关于方法内部调用,@Async注解会失效

    public class QueryServiceImpl implements QueryService {
    	@Override
    	public void A() {
    		System.out.println("QueryServiceImpl.A");
    		B();
    	}
    
    	@Async
    	@Override
    	public void B() {
    		System.out.println("QueryServiceImpl.B");
    	}
    }
    
    

    ​ 失效原因:A方法中调用B方法,调用即为this.B(),this对象为原始的对象,并不是增强后代理对象,当然不能生效了。建议重构分开调用,如果硬是需要内部调用则是只能通过获取代理对象来实现。

    @Component("q")
    public class QueryServiceImpl implements QueryService {
    
    	@Autowired
    	private ApplicationContext applicationContext;
    
    
    	@Override
    	public void A() {
    		System.out.println("QueryServiceImpl.A");
    		QueryService queryService = (QueryService)applicationContext.getBean("q");
    		queryService.B();
    	}
    
    	@Async
    	@Override
    	public void B() {
    		System.out.println("QueryServiceImpl.B");
    	}
    }
    
    

    参考

    查看更多文章关注公众号:好奇心森林
    Wechat

  • 相关阅读:
    [转]进程与线程及其区别
    [转]工厂模式
    [转]Filter实现处理中文乱码,转义html标签,过滤敏感词
    [转]JAVA设计模式之单例模式
    [转]Servlet 中文乱码问题及解决方案剖析
    Servlet作业2-将表单提交的商品信息输出到页面中
    Servlet作业1-实现注册登录
    [转] ServletContext 与application的异同
    [转]servlet中的service, doGet, doPost方法的区别和联系
    [转]Servlet 3.0 新特性详解
  • 原文地址:https://www.cnblogs.com/hackingForest/p/13173378.html
Copyright © 2011-2022 走看看