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

做软装素材从哪些网站找西楚房产网宿迁房产网

做软装素材从哪些网站找,西楚房产网宿迁房产网,励志做的很好的网站,网站首页动画代码2019独角兽企业重金招聘Python工程师标准 在上文Spring Aop之Target Source详解中#xff0c;我们讲解了Spring是如何通过封装Target Source来达到对最终获取的目标bean进行封装的目的。其中我们讲解到#xff0c;Spring Aop对目标bean进行代理是通过Annotatio… 2019独角兽企业重金招聘Python工程师标准        在上文Spring Aop之Target Source详解中我们讲解了Spring是如何通过封装Target Source来达到对最终获取的目标bean进行封装的目的。其中我们讲解到Spring Aop对目标bean进行代理是通过AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization()进行的Spring Aop的代理主要分为三个步骤获取所有的Advisor过滤可应用到当前bean的Adivsor和使用Advisor为当前bean生成代理对象。本文主要对这三步中的第一步获取所有的Advisor进行讲解。 1. 骨架方法        首先我们看看postProcessAfterInitialization()方法的实现 public Object postProcessAfterInitialization(Nullable Object bean, String beanName) throws BeansException {if (bean ! null) {// 获取当前bean的key如果beanName不为空则以beanName为key如果为FactoryBean类型// 前面还会添加符号如果beanName为空则以当前bean对应的class为keyObject cacheKey getCacheKey(bean.getClass(), beanName);// 判断当前bean是否正在被代理如果正在被代理则不进行封装if (!this.earlyProxyReferences.contains(cacheKey)) {// 对当前bean进行封装return wrapIfNecessary(bean, beanName, cacheKey);}}return bean; }从上述代码可以看出对目标bean的封装是主要是通过wrapIfNecessary()方法进行的该方法就是Spring对目标bean进行代理的骨架方法。如下是该方法的实现 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 判断当前bean是否在TargetSource缓存中存在如果存在则直接返回当前bean。这里进行如此判断的// 原因是在上文中我们讲解了如何通过自己声明的TargetSource进行目标bean的封装在封装之后其实// 就已经对封装之后的bean进行了代理并且添加到了targetSourcedBeans缓存中。因而这里判断得到// 当前缓存中已经存在当前bean则说明该bean已经被代理过这样就可以直接返回当前bean。if (StringUtils.hasLength(beanName) this.targetSourcedBeans.contains(beanName)) {return bean;}// 这里advisedBeans缓存了已经进行了代理的bean如果缓存中存在则可以直接返回if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}// 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean自带的bean是// 不用进行代理的shouldSkip()则用于判断当前bean是否应该被略过if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {// 对当前bean进行缓存this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// 获取当前bean的Advices和AdvisorsObject[] specificInterceptors getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors ! DO_NOT_PROXY) {// 对当前bean的代理状态进行缓存this.advisedBeans.put(cacheKey, Boolean.TRUE);// 根据获取到的Advices和Advisors为当前bean生成代理对象Object proxy createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));// 缓存生成的代理bean的类型并且返回生成的代理beanthis.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean; }在上述骨架方法中Spring主要进行了三件事 判断当前bean是否已经生成过代理对象或者是否是应该被略过的对象是则直接返回否则进行下一步获取当前bean的Advisors和Advices如果当前bean不需要代理则返回DO_NOT_PROXY通过生成的Advisors和Advices为目标bean生成代理对象。       关于上述骨架方法这里需要说明两个点 shouldSkip()方法中对当前bean判断是否应该略过时其主要做了两件事a. 为当前bean生成需要代理的Advisorsb. 判断生成的Advisor是否为AspectJPointcutAdvisor类型。因而实际上判断略过的过程就是判断是否为AspectJPointcutAdvisor判断这个类的原因在于Spring Aop的切面和切点的生成也可以通过在xml文件中使用aop:config/标签进行。这个标签最终解析得到的Adivsor类型就是AspectJPointcutAdvisor类型的因为其在解析aop:config/的时候就已经生成了Advisor因而这里需要对这种类型的Advisor进行略过。这里aop:config/也是一种自定义标签关于其解析过程读者可以参照本人前面的博文自行阅读器源码getAdvicesAndAdvisorsForBean()方法就其名称而言是获取Advisors和Advices但实际上其返回值是一个Advisor的数组。Spring Aop在为目标bean获取需要进行代理的切面逻辑的时候最终得到的是Advisor这里Advice表示的是每个切面逻辑中使用Before、After和Around等需要织入的代理方法。因为每个代理方法都表示一个Advice并且每个代理方法最终都会生成一个Advisor因而Advice和Advisor就本质而言其实没有太大的区别。Advice表示需要织入的切面逻辑而Advisor则表示将切面逻辑进行封装之后的织入者。2. 切面的生成        虽然在shouldSkip()方法中会为当前bean生成Advisor但是在getAdvicesAndAdvisorsForBean()中也还是会获取一次只不过在第一次生成的时候会将得到的Advisor都进行缓存因而第二次获取时可以直接从缓存中获取。我们这里还是以getAdvicesAndAdvisorsForBean()方法为准来进行讲解。如下是该方法的源码 protected Object[] getAdvicesAndAdvisorsForBean(Class? beanClass, String beanName, Nullable TargetSource targetSource) {// 为目标bean生成AdvisorListAdvisor advisors findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;}return advisors.toArray(); }我们继续看findEligibleAdvisors()方法 protected ListAdvisor findEligibleAdvisors(Class? beanClass, String beanName) {// 将当前系统中所有的切面类的切面逻辑进行封装从而得到目标AdvisorListAdvisor candidateAdvisors findCandidateAdvisors();// 对获取到的所有Advisor进行判断看其切面定义是否可以应用到当前bean从而得到最终需要应用的AdvisorListAdvisor eligibleAdvisors findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);// 提供的hook方法用于对目标Advisor进行扩展extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) {// 对需要代理的Advisor按照一定的规则进行排序eligibleAdvisors sortAdvisors(eligibleAdvisors);}return eligibleAdvisors; }在上述方法中Spring Aop首先获取到了系统中所有的切面逻辑并将其封装为了Advisor对象然后通过遍历Advisor判断哪些Advisor是可以应用到当前bean的最后将需要织入的Advisor返回。这里我们看看findCandidateAdvisors()的源码 protected ListAdvisor findCandidateAdvisors() {// 找到系统中实现了Advisor接口的beanListAdvisor advisors super.findCandidateAdvisors();if (this.aspectJAdvisorsBuilder ! null) {// 找到系统中使用Aspect标注的bean并且找到该bean中使用BeforeAfter等标注的方法// 将这些方法封装为一个个Advisoradvisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());}return advisors; }可以看到findCandidateAdvisors()主要是通过两种方式获取切面逻辑一种是在系统中找到实现了Advisor接口的所有类另一种是在找到系统中使用Aspect标注的类并将其切面逻辑封装为Advisor这两种Advisor都有可能是我们需要进行织入的切面逻辑。这里super.findCandidateAdvisors()方法最终调用的是BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans()方法我们首先看看该方法的实现 public ListAdvisor findAdvisorBeans() {String[] advisorNames null;synchronized (this) {advisorNames this.cachedAdvisorBeanNames;if (advisorNames null) {// 获取当前BeanFactory中所有实现了Advisor接口的bean的名称advisorNames BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);this.cachedAdvisorBeanNames advisorNames;}}if (advisorNames.length 0) {return new LinkedList();}// 对获取到的实现Advisor接口的bean的名称进行遍历ListAdvisor advisors new LinkedList();for (String name : advisorNames) {// isEligibleBean()是提供的一个hook方法用于子类对Advisor进行过滤这里默认返回值都是trueif (isEligibleBean(name)) {// 如果当前bean还在创建过程中则略过其创建完成之后会为其判断是否需要织入切面逻辑if (this.beanFactory.isCurrentlyInCreation(name)) {if (logger.isDebugEnabled()) {logger.debug(Skipping currently created advisor name );}} else {try {// 将当前bean添加到结果中advisors.add(this.beanFactory.getBean(name, Advisor.class));} catch (BeanCreationException ex) {// 对获取过程中产生的异常进行封装Throwable rootCause ex.getMostSpecificCause();if (rootCause instanceof BeanCurrentlyInCreationException) {BeanCreationException bce (BeanCreationException) rootCause;String bceBeanName bce.getBeanName();if (bceBeanName ! null this.beanFactory.isCurrentlyInCreation(bceBeanName)) {if (logger.isDebugEnabled()) {logger.debug(Skipping advisor name with dependency on currently created bean: ex.getMessage());}continue;}}throw ex;}}}}return advisors; }这里findAdvisorBeans()方法逻辑其实非常简单其主要是在BeanFactory中找打实现了Advisor接口的类然后通过hook方法判断子类是否需要对Advisor进行过滤最后将过滤之后的Advisor返回。        接下来我们看看BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors()的实现 public ListAdvisor buildAspectJAdvisors() {ListString aspectNames this.aspectBeanNames;if (aspectNames null) {synchronized (this) {aspectNames this.aspectBeanNames;if (aspectNames null) {ListAdvisor advisors new LinkedList();aspectNames new LinkedList();// 获取当前BeanFactory中所有的beanString[] beanNames BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);// 对获取到的所有bean进行循环遍历for (String beanName : beanNames) {// 判断当前bean是否为子类定制的需要过滤的beanif (!isEligibleBean(beanName)) {continue;}// 获取当前遍历的bean的Class类型Class? beanType this.beanFactory.getType(beanName);if (beanType null) {continue;}// 判断当前bean是否使用了Aspect注解进行标注if (this.advisorFactory.isAspect(beanType)) {aspectNames.add(beanName);// 对于使用了Aspect注解标注的bean将其封装为一个AspectMetadata类型。// 这里在封装的过程中会解析Aspect注解上的参数指定的切面类型如perthis// 和pertarget等。这些被解析的注解都会被封装到其perClausePointcut属性中AspectMetadata amd new AspectMetadata(beanType, beanName);// 判断Aspect注解中标注的是否为singleton类型默认的切面类都是singleton// 类型if (amd.getAjType().getPerClause().getKind() PerClauseKind.SINGLETON) {// 将BeanFactory和当前bean封装为MetadataAwareAspect-// InstanceFactory对象这里会再次将Aspect注解中的参数都封装// 为一个AspectMetadata并且保存在该factory中MetadataAwareAspectInstanceFactory factory new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);// 通过封装的bean获取其Advice如BeforeAfter等等并且将这些// Advice都解析并且封装为一个个的AdvisorListAdvisor classAdvisors this.advisorFactory.getAdvisors(factory);// 如果切面类是singleton类型则将解析得到的Advisor进行缓存// 否则将当前的factory进行缓存以便再次获取时可以通过factory直接获取if (this.beanFactory.isSingleton(beanName)) {this.advisorsCache.put(beanName, classAdvisors);} else {this.aspectFactoryCache.put(beanName, factory);}advisors.addAll(classAdvisors);} else {// 如果Aspect注解标注的是perthis和pertarget类型说明当前切面// 不可能是单例的因而这里判断其如果是单例的则抛出异常if (this.beanFactory.isSingleton(beanName)) {throw new IllegalArgumentException(Bean with name beanName is a singleton, but aspect instantiation model is not singleton);}// 将当前BeanFactory和切面bean封装为一个多例类型的FactoryMetadataAwareAspectInstanceFactory factory new PrototypeAspectInstanceFactory(this.beanFactory, beanName);// 对当前bean和factory进行缓存this.aspectFactoryCache.put(beanName, factory);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}}this.aspectBeanNames aspectNames;return advisors;}}}if (aspectNames.isEmpty()) {return Collections.emptyList();}// 通过所有的aspectNames在缓存中获取切面对应的Advisor这里如果是单例的则直接从advisorsCache// 获取如果是多例类型的则通过MetadataAwareAspectInstanceFactory立即生成一个ListAdvisor advisors new LinkedList();for (String aspectName : aspectNames) {ListAdvisor cachedAdvisors this.advisorsCache.get(aspectName);// 如果是单例的Advisor bean则直接添加到返回值列表中if (cachedAdvisors ! null) {advisors.addAll(cachedAdvisors);} else {// 如果是多例的Advisor bean则通过MetadataAwareAspectInstanceFactory生成MetadataAwareAspectInstanceFactory factory this.aspectFactoryCache.get(aspectName);advisors.addAll(this.advisorFactory.getAdvisors(factory));}}return advisors; }对于通过Aspect注解获取切面逻辑的方法这里的逻辑也比较简单Spring首先会过滤得到BeanFactory中所有标注有Aspect的类然后对该注解参数进行解析判断其环绕的目标bean是单例的还是多例的。如果是单例的则直接缓存到advisorsCache中如果是多例的则将生成Advisor的factory进行缓存以便每次获取时都通过factory获取一个新的Advisor。上述方法中主要是对Aspect注解进行了解析我们前面讲过Spring Aop的Advisor对应的是Advice而每个Advice都是对应的一个Before或者After等标注方法的切面逻辑这里对这些切面逻辑的解析过程就在上述的advisorFactory.getAdvisors(factory)方法调用中。这里我们看看该方法的实现 public ListAdvisor getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {// 获取当前切面类的Class类型Class? aspectClass aspectInstanceFactory.getAspectMetadata().getAspectClass();// 获取当前切面bean的名称String aspectName aspectInstanceFactory.getAspectMetadata().getAspectName();// 对当前切面bean进行校验主要是判断其切点是否为perflow或者是percflowbelowSpring暂时不支持// 这两种类型的切点validate(aspectClass);// 将当前aspectInstanceFactory进行封装这里LazySingletonAspectInstanceFactoryDecorator// 使用装饰器模式主要是对获取到的切面实例进行了缓存保证每次获取到的都是同一个切面实例MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);ListAdvisor advisors new LinkedList();// 这里getAdvisorMethods()会获取所有的没有使用Pointcut注解标注的方法然后对其进行遍历for (Method method : getAdvisorMethods(aspectClass)) {// 判断当前方法是否标注有BeforeAfter或Around等注解如果标注了则将其封装为一个AdvisorAdvisor advisor getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);if (advisor ! null) {advisors.add(advisor);}}// 这里的isLazilyInstantiated()方法判断的是当前bean是否应该被延迟初始化其主要是判断当前// 切面类是否为perthispertarget或pertypewithiin等声明的切面。因为这些类型所环绕的目标bean// 都是多例的因而需要在运行时动态判断目标bean是否需要环绕当前的切面逻辑if (!advisors.isEmpty() lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {// 如果Advisor不为空并且是需要延迟初始化的bean则在第0位位置添加一个同步增强器// 该同步增强器实际上就是一个BeforeAspect的AdvisorAdvisor instantiationAdvisor new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);advisors.add(0, instantiationAdvisor);}// 判断属性上是否包含有DeclareParents注解标注的需要新添加的属性如果有则将其封装为一个Advisorfor (Field field : aspectClass.getDeclaredFields()) {Advisor advisor getDeclareParentsAdvisor(field);if (advisor ! null) {advisors.add(advisor);}}return advisors; }在上述getAdvisors()方法中Spring会遍历当前切面类所有的方法包括父类和父接口的方法找到其中没有使用Pointcut注解标注的方法然后对找到的方法进行遍历将其封装为一个Advisor。这里我们继续看封装为Advisor的方法 public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {// 校验当前切面类是否使用了perflow或者percflowbelow标识的切点Spring暂不支持这两种切点validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());// 获取当前方法中BeforeAfter或者Around等标注的注解并且获取该注解的值将其// 封装为一个AspectJExpressionPointcut对象AspectJExpressionPointcut expressionPointcut getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());if (expressionPointcut null) {return null;}// 将获取到的切点切点方法等信息封装为一个Advisor对象也就是说当前Advisor包含有所有// 当前切面进行环绕所需要的信息return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName); }到这里Spring才将BeforeAfter或Around标注的方法封装为了一个Advisor对象。需要说明的是这里封装成的Advisor对象只是一个半成品。所谓的半成品指的是此时其并没有对切点表达式进行解析其还只是使用一个字符串保存在AspectJExpressionPointcut对象中只有在真正使用当前Advice逻辑进行目标bean的环绕的时候才会对其进行解析。 3. 小结        本文主要讲解了Spring是如何获取所有的Advisor的即首先获取BeanFactory中所有实现了Advisor接口的bean然后获取BeanFactory中所有标注了Aspect注解的bean解析该bean中的所有的切面逻辑并且封装为一个个Advisor这两种方式得到的Advisor都有可能是最终会应用到目标bean上的切面逻辑。需要注意的是这里获取到的Advisor并没有对切点表达式进行解析实际的解析过程是在判断当前bean是否可以应用到目标bean时进行的。这也是一个小小的优化因为解析切点表达式的过程是一个比较复杂的过程。 转载于:https://my.oschina.net/zhangxufeng/blog/1929863
http://www.pierceye.com/news/372664/

相关文章:

  • 建设网站的教程免费的wordpress分类在哪设置
  • 电子书网站 跟我学做家常菜800网站建设与维护 教学大纲
  • 河南省住房城乡建设主管部门网站wordpress还有人在用吗
  • 好口碑关键词优化沈阳企业关键词优化
  • 外汇自动跟单网站开发wordpress支持中文
  • 南宁网站建设推广教育类网站框架
  • 定制网站建设服务公司摄影设计师招聘
  • 地图 添加到网站观点网站
  • 给分管领导网站建设情况汇报怎么写企业网站的发展历史
  • 佛山营销网站建设费用app制作器下载软件
  • 如何将优酷视频上传到自己网站万能网
  • 域名销售网站wordpress 数据库配置文件
  • 广州营销型网站建设怎么样做网站必须要认证吗
  • 网站开发主要内容免费商城平台
  • 青岛建站方案海兴县网站建设公司
  • 网站文案框架兰州网页制作公司网站
  • 专业网站有哪些平台wordpress那个版本
  • 网站建设按钮详情页设计图
  • 杭州公司注册代理中介深圳关键词优化软件
  • 乐清网站制作公司电话免费做初中试卷的网站
  • 注册一个网站的流程反向代理服务器做wordpress外网
  • 沁阳网站建设tomcat建网站
  • 品牌网站建设公司推荐网站建设公司3lue
  • 装修公司网站模版徐州品牌网站建设
  • 医疗网站建设计划书一级消防工程师考试科目
  • 信誉好的网站建设公司网站关停公告怎么做
  • 画图在什么网站上做兼职广告词
  • 昆明购物网站建设企业网络设计方案预算
  • 浙江省建设工程质监站网站什么是营销型网站建设
  • 做网站需要云数据库吗企业做网页还是网站