当前位置: 首页 > news >正文

手机网站设计公司立找亿企邦惠州网站制作软件

手机网站设计公司立找亿企邦,惠州网站制作软件,德州网站建设教程,山东省建设执业师网站文章目录 概述小结好文推荐 概述 在Spring中调用线程将在调用含有Async注释的方法时立即返回#xff0c;Spring是如何做到的呢#xff1f;其实是其对标注Async注解的类做了代理#xff0c;比如下面的类Async-AnnotationExample。 public class AsyncAnnotationExample {As… 文章目录 概述小结好文推荐 概述 在Spring中调用线程将在调用含有Async注释的方法时立即返回Spring是如何做到的呢其实是其对标注Async注解的类做了代理比如下面的类Async-AnnotationExample。 public class AsyncAnnotationExample {Asyncpublic CompletableFutureString doSomething() {// 1.创建futureCompletableFutureString result new CompletableFutureString();// 2.模拟任务执行try {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() doSomething);} catch (Exception e) {e.printStackTrace();}result.complete(done);// 3.返回结果return result;} }由于AsyncAnnotationExample类中方法doSomething被标注了Async注解所以Spring框架在开启异步处理后会对AsyncAnnotationExample的实例进行代理代理后的类代码框架如下所示。 public class AsyncAnnotationExampleProxy {public AsyncAnnotationExample getAsyncTask() {return asyncTask;}public void setAsyncAnnotationExample(AsyncAnnotationExample asyncTask) {this.asyncTask asyncTask;}private AsyncAnnotationExample asyncTask;private TaskExecutor executor new SimpleAsyncTaskExecutor();public CompletableFutureString dosomthingAsyncFuture() {return CompletableFuture.supplyAsync(new SupplierString() {Overridepublic String get() {try {return asyncTask.dosomthing().get();} catch (Throwable e) {throw new CompletionException(e);}}},executor);} }如上代码所示Spring会对AsyncAnnotationExample类进行代理并且会把AsyncAnnotationExample的实例注入AsyncAnnotationExampleProxy内部当我们调用AsyncAnnotationExample的dosomthing方法时实际调用的是AsyncAnnotation ExampleProxy的dosomthing方法后者使用CompletableFuture.supplyAsync开启了一个异步任务其马上返回一个CompletableFuture对象并且使用默认的SimpleAsync TaskExecutor线程池作为异步处理线程然后在异步任务内具体调用了AsyncAnnotationExample实例的dosomthing方法。 默认情况下Spring框架是使用Cglib对标注Async注解的方法进行代理的具体拦截器是AnnotationAsyncExecutionInterceptor我们看看其invoke方法。 public Object invoke(final MethodInvocation invocation) throws Throwable {//1.被代理的目标对象Class? targetClass (invocation.getThis() ! null ? AopUtils.getTargetClass(invocation.getThis()) : null);//2. 获取被代理的方法Method specificMethod ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);final Method userDeclaredMethod BridgeMethodResolver.findBridgedMethod(specificMethod);//3. 判断使用哪个执行器执行被代理的方法AsyncTaskExecutor executor determineAsyncExecutor(userDeclaredMethod);if (executor null) {throw new IllegalStateException(No executor specified and no default executor set on AsyncExecutionInterceptor either);}//4. 使用Callable包装要执行的方法CallableObject 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;};//5. 提交包装的Callable任务到指定执行器执行return doSubmit(task, executor, invocation.getMethod().getReturnType()); }·代码1获取被代理的目标对象的Class对象本例中为class:com.artisan.async.AsyncProgram.AsyncAnnotationExample的Class对象 ·代码2获取被代理的方法本例中为public java.util.concurrent.CompletableFuture:com.artisan.async.AsyncProgram.AsyncAnnotationExample.dosomthing() ·代码3根据规则获取使用哪个执行器TaskExecutor执行被代理的方法其代码如下所示。 private final MapMethod, AsyncTaskExecutor executors new ConcurrentHashMap(16); protected AsyncTaskExecutor determineAsyncExecutor(Method method) {//4.1获取对应方法的执行器AsyncTaskExecutor executor this.executors.get(method);//4.2不存在则按照规则查找if (executor null) {//4.2.1 如果注解Async中指定了执行器名称Executor targetExecutor;String qualifier getExecutorQualifier(method);if (StringUtils.hasLength(qualifier)) {targetExecutor findQualifiedExecutor(this.beanFactory, qualifier);}//4.2.2 获取默认执行器else {targetExecutor this.defaultExecutor;if (targetExecutor null) {synchronized (this.executors) {if (this.defaultExecutor null) {this.defaultExecutor getDefaultExecutor(this.beanFactory);}targetExecutor this.defaultExecutor;}}}//4.2.3if (targetExecutor null) {return null;}//4.2.4 添加执行器到缓存executor (targetExecutor instanceof AsyncListenableTaskExecutor ?(AsyncListenableTaskExecutor) targetExecutor : new TaskExecutorAdapter(targetExecutor));this.executors.put(method, executor);}//4.3返回查找的执行器return executor; }代码4.1从缓存executors中尝试获取method方法对应的执行器如果存在则直接执行代码4.3返回否则执行代码4.2.1判断方法的注解Async中是否指定了执行器名称如果有则尝试从Spring的bean工厂内获取该名称的执行器的实例否则执行代码4.2.2获取默认的执行器SimpleAsyncTaskExecutor然后代码4.2.4把执行器放入缓存。 到这里就探讨完成了AnnotationAsyncExecutionInterceptor的invoke方法内代码3是如何确定那个执行器然后在invoke方法中的代码4使用Callable包装要执行的方法代码5提交包装的Callable任务到指定执行器。 到这里所有的执行使用的都是调用线程调用线程提交异步任务到执行器后就返回了异步任务真正执行的是具体执行器中的线程。下面我们看看代码5 doSubmit的代码。 protected Object doSubmit(CallableObject task, AsyncTaskExecutor executor, Class? returnType) {//5.1判断方法返回值是否为CompletableFuture类型或者是其子类if (CompletableFuture.class.isAssignableFrom(returnType)) {return CompletableFuture.supplyAsync(() - {try {return task.call();}catch (Throwable ex) {throw new CompletionException(ex);}}, executor);}//5.2判断返回值类型是否为ListenableFuture类型或者是其子类else if (ListenableFuture.class.isAssignableFrom(returnType)) {return ((AsyncListenableTaskExecutor) executor).submitListenable(task);}//5.3判断返回值类型是否为ListenableFuture类型或者是其子类else if (Future.class.isAssignableFrom(returnType)) {return executor.submit(task);}//5.4其他情况下没有返回值else {executor.submit(task);return null;} }·代码5.1判断方法返回值是否为CompletableFuture类型或者是其子类如果是则把任务使用CompletableFuture.supplyAsync方法提交到线程池executor执行该方法会马上返回一个CompletableFuture对象。 ·代码5.2判断方法返回值是否为ListenableFuture类型或者是其子类如果是则把任务提交到线程池executor执行该方法会马上返回一个ListenableFuture对象。 ·代码5.3判断方法返回值是否为Future类型或者是其子类如果是则把任务提交到线程池executor执行该方法会马上返回一个Future对象。 ·代码5.4说明方法不需要返回值直接提交任务到线程池executor后返回null。 上面我们讲解了代理拦截器AnnotationAsyncExecutionInterceptor的invoke方法如何对标注Async的方法进行处理实现异步执行的。其实还有一部分还没讲前面说了要开始异步处理必须使用EnableAsync注解或者task:annotation-driven/来开启异步处理那么这两个部分背后到底做了什么呢下面我们就来一探究竟。 首先我们看看添加EnableAsync注解后发生了什么在Spring容器启动的过程中会有一系列扩展接口对Bean的元数据定义、初始化、实例化做拦截处理也存在一些处理器类可以动态地向Spring容器添加一些框架需要使用的Bean实例。其中ConfigurationClassPostProcessor处理器类则是用来解析注解类并把其注册到Spring容器中的其可以解析标注Configuration、Component、ComponentScan、Import、ImportResource等的Bean。当我们使用context:annotation-config/或者context:component-scan/时Spring容器会默认把ConfigurationClassPostProcessor处理器注入Spring容器。 而EnableAsync的定义如下 Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Import(AsyncConfigurationSelector.class) public interface EnableAsync { ... }所以我们添加了EnableAsync注解后ConfigurationClassPostProcessor会解析其中的Import(AsyncConfigurationSelector.class)并把AsyncConfigurationSelector的实例注入Spring容器其代码如下所示。 public class AsyncConfigurationSelector extends AdviceModeImportSelectorEnableAsync {private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME org.springframework.scheduling.aspectj.AspectJAsyncConfiguration;OverrideNullablepublic 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;}} }AsyncConfigurationSelector实现了ImportSelector接口的selectImports方法根据AdviceMode参数返回需要导入到Spring容器的Bean的全路径包名。该方法会在ConfigurationClassPostProcessor中的ConfigurationClassParser类中调用。默认情况下的adviceMode为PROXY所以会把ProxyAsyncConfiguration的实例注入Spring容器。 ProxyAsyncConfiguration的代码如下所示。 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() {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(proxyTarget Class));bpp.setOrder(this.enableAsync.IntegergetNumber(order));return bpp;}}如上代码ProxyAsyncConfiguration的asyncAdvisor方法添加了Bean注解所以该方法返回的Bean也会被注入Spring容器。该方法创建了AsyncAnnotationBean PostProcessor处理器所以AsyncAnnotationBeanPostProcessor的一个实例会被注入Spring容器中由于其实现了BeanFactoryAware接口所以Spring框架会调用其setBeanFactory(BeanFactory beanFactory)方法把Spring BeanFactory(存放bean的容器)注入该BeansetBeanFactory方法代码如下所示。 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; }如上代码创建了一个AsyncAnnotationAdvisor的实例并保存到了AsyncAnnotation BeanPostProcessor的advisor变量。Spring中每个AsyncAnnotationAdvisor都包含一个Advice切面逻辑和一个PointCut切点也就是会对符合PointCut的方法使用Advice进行功能增强对应Advice和PointCut是在AsyncAnnotationAdvisor构造函数内创建的。 public AsyncAnnotationAdvisor(Nullable SupplierExecutor executor, Nullable SupplierAsyncUncaughtExceptionHandler exceptionHandler) {//6.1.异步注解类型SetClass? 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) {}//6.2创建切面逻辑this.advice buildAdvice(executor, exceptionHandler);//6.3创建切点this.pointcut buildPointcut(asyncAnnotationTypes); }如上代码6.1收集注解Async和javax.ejb.Asynchronous到asyncAnnotationTypes代码6.2则创建Advice其代码如下所示。 protected Advice buildAdvice(Nullable SupplierExecutor executor, Nullable SupplierAsyncUncaughtExceptionHandler exceptionHandler) {AnnotationAsyncExecutionInterceptor interceptor new AnnotationAsyncExecutionInterceptor(null);interceptor.configure(executor, exceptionHandler);return interceptor; }由上述代码可知这里创建了AnnotationAsyncExecutionInterceptor拦截器作为切面逻辑。下面看看代码6.3如何创建切点。 protected Pointcut buildPointcut(SetClass? 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); }在上述代码中使用收集的注解集合asyncAnnotationTypes并在每个注解处创建了一个AnnotationMatchingPointcut作为切点AnnotationMatchingPointcut内部的AnnotationClassFilter的方法matches则作为某个方法是否满足切点的条件具体代码如下所示。 public boolean matches(Class? clazz) {return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(clazz, this.annotationType) :clazz.isAnnotationPresent(this.annotationType)); }由如上代码可知判断方法通过是否有注解Async为依据来判断方法是否符合切点。 到此我们把AsyncAnnotationBeanPostProcessor的setBeanFactory(BeanFactory bean-Factory)方法逻辑讲解完毕了其内部保存了一个AsyncAnnotationAdvisor对象用来对Spring容器中符合条件这里为含有Async注解的方法的Bean的Bean的方法进行功能增强下面我们看看AsyncAnnotationBeanPostProcessor的postProcess AfterInitialization方法是如何对这些符合条件的Bean进行代理的。 public Object postProcessAfterInitialization(Object bean, String beanName) {...if (isEligible(bean, beanName)) {//7.1ProxyFactory proxyFactory prepareProxyFactory(bean, beanName);if (!proxyFactory.isProxyTargetClass()) {evaluateProxyInterfaces(bean.getClass(), proxyFactory);}//7.2 设置拦截器proxyFactory.addAdvisor(this.advisor);customizeProxyFactory(proxyFactory);//7.3 获取代理类return proxyFactory.getProxy(getProxyClassLoader());}// No proxy needed.return bean; }如上代码7.1使用prepareProxyFactory创建了代理工厂其代码如下所示。 protected ProxyFactory prepareProxyFactory(Object bean, String beanName) {ProxyFactory proxyFactory new ProxyFactory();proxyFactory.copyFrom(this);proxyFactory.setTarget(bean);return proxyFactory; }代码7.2则设置在其setBeanFactory方法内创建的AsyncAnnotationAdvisor对象作为Advisor代码7.3从代理工厂获取代理后的Bean实例并返回到Spring容器所以当我们调用含有Async注解的Bean的方法时候实际调用的是被代理后的Bean。 当我们调用被代理的类的方法时代理类内部会先使用AsyncAnnotationAdvisor中的PointCut进行比较看其是否符合切点条件方法是否含有Async注解如果不符合则直接调用被代理的对象的原生方法否则调用AsyncAnnotationAdvisor内部的AnnotationAsyncExecutionInterceptor进行拦截异步处理。 在了解添加EnableAsync注解后会发生什么后下面我们来看看当添加标签task:annotation-driven/开启异步处理时背后又发生了什么在Spring中对于标签XXX:/总是会存在名称为XXXTaskNamespaceHandler的处理器负责该标签的解析所以对于标签自然存在TaskNamespaceHandler处理器负责其解析其代码如下所示。 public class TaskNamespaceHandler extends NamespaceHandlerSupport {Overridepublic void init() {this.registerBeanDefinitionParser(annotation-driven, new AnnotationDrivenBeanDefinitionParser());this.registerBeanDefinitionParser(executor, new ExecutorBeanDefinitionParser());this.registerBeanDefinitionParser(scheduled-tasks, new ScheduledTasksBeanDefinitionParser());this.registerBeanDefinitionParser(scheduler, new SchedulerBeanDefinitionParser());} }由如上代码可知task:annotation-driven/是使用AnnotationDrivenBeanDefinitionParser来进行解析的下面我们看看其parse方法。 public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { ...OverrideNullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {Object source parserContext.extractSource(element);...//8.1 String mode element.getAttribute(mode);if (aspectj.equals(mode)) {// modeaspectjregisterAsyncExecutionAspect(element, parserContext);}else {//8.2 modeproxyif (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {parserContext.getReaderContext().error(Only one AsyncAnnotationBeanPostProcessor may exist within the context., source);}else {BeanDefinitionBuilder builder BeanDefinitionBuilder.genericBeanDefinition(org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor);builder.getRawBeanDefinition().setSource(source);String executor element.getAttribute(executor);if (StringUtils.hasText(executor)) {builder.addPropertyReference(executor, executor);}String exceptionHandler element.getAttribute(exception-handler);if (StringUtils.hasText(exceptionHandler)) {builder.addPropertyReference(exceptionHandler, exceptionHandler);}if (Boolean.valueOf(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {builder.addPropertyValue(proxyTargetClass, true);}registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);}}//8.3 Finally register the composite component.parserContext.popAndRegisterContainingComponent();return null;} }由如上代码可知其主要是用来创建AsyncAnnotationBeanPostProcessor在Spring容器中的元数据定义并注册到Spring容器中剩下的流程就与基于EnableAsync注解开启异步处理的流程一样了。 小结 我们梳理如何使用Spring框架中的Async进行异步处理以及其内部如何使用代理的方式来实现并且可知使用Async实现异步编程属于声明式编程一般情况下不需要我们显式创建线程池并提交任务到线程池这大大减轻了的负担 好文推荐 一文彻底讲透Async注解的原理和使用方法
http://www.tj-hxxt.cn/news/219031.html

相关文章:

  • 网站自然排名往后掉秦皇岛乾兴建设工程
  • wordpress 默认站点做视频网站收入
  • 公司网站域名是什么湖南手机版建站系统信息
  • 运城做网站网络加速器哪个好
  • 怎样使用二维码做网站双语cms网站
  • 网站开发成本最低多少钱怎么做网站推广最有效
  • 一键免费建立网站网站建设公司被网监大队检查
  • 医生可以自己做网站吗网站开发使用哪种工具好
  • 网站语言选择曲靖做网站的公司
  • 做外贸需要用到什么网站国外的网站服务商
  • js网站一键变灰wordpress 回复楼层
  • 网站开发公司成都dw怎样去除网站做的页面模板
  • 自己搭建视频播放网站扬中网站建设策划
  • 北京网站维护高中信息技术网站建设
  • 提供网站建设框架机械做网站
  • 网站后台生成文章很慢建网站怎么赚流量
  • 在线做编程题的网站视频制作免费
  • 洛阳建网站公司scrm服务商
  • 沈阳网站建设选网龙怎么样建网站啊
  • 手机版网站推荐赣州本地网
  • 自己怎么样做游戏网站html改变字体大小代码
  • 做商业广告有什么网站好推销的专业网站优化seo
  • 南充建网站的资料百度编辑器wordpress
  • 网站开发怎么收客户费广西网站建设公司哪家好
  • 图片链接生成网站深圳营销型网站建设推广服务
  • 北京上云网站建设公司中国视觉设计网
  • 哪个网站做课件能赚钱京网站制作公司
  • 重庆网站设计制造厂家做设计在哪个网站上找高清图片大全
  • 宣武上海网站建设河北响应式网站建设
  • 吉林省住房和城乡建设部网站外汇直播网站建设开发