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

一天一元网站建设百度广告代运营公司

一天一元网站建设,百度广告代运营公司,hbuilder网站开发过程,国度网络网站建设随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666) from:Spring 源码分析(三) —— AOP(二)Spring AOP 整体架构 - 水门-kay的个人页面 - OSCHINA - 中文开源技术交流社区 Spri…

随时随地技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666)

from:Spring 源码分析(三) —— AOP(二)Spring AOP 整体架构 - 水门-kay的个人页面 - OSCHINA - 中文开源技术交流社区

Spring AOP 架构

        先是生成代理对象,然后是拦截器的作用,最后是编织的具体实现。这是AOP实现的三个步骤,当然Spring AOP也是一样。

        而从Spring AOP整体架构上看其核心都是建立在代理上的。当我们建立增强实例时,我们必须先使用 ProxyFactory 类加入我们需要织入该类的所有增强,然后为该类创建代理。一般而言,AOP实现代理的方法有三种,而 Spring 内部用到了其中的两种方法:动态代理和静态代理,而动态代理又分为JDK动态代理和CGLIB代理。而前面提到的 ProxyFactory 类控制着 Spring AOP 中的织入和创建代理的过程。在真正创建代理之前,我们必须指定被增强对象或者目标对象。我们是通过 setTarget() 方法来完成这个步骤的。而 ProxyFactory 内部将生成代理的过程全部转给 DefaultAopProxyFactory 对象来完成,然后根据设置转给其他的类来完成。下面是 Spring AOP 生成代理的原理图:

        而特别需要注意的是,在 Spring AOP 中,一个 Advisor(通知者,也翻作 通知器或者增强器)就是一个切面,他的主要作用是整合切面增强设计(Advice)和切入点设计(Pointcut)。Advisor有两个子接口:IntroductionAdvisor 和 PointcutAdvisor,基本所有切入点控制的 Advisor 都是由 PointcutAdvisor 实现的。而下面的是Spring AOP的整体架构图

        乍一看,非常的复杂,但如果结合上面的Spring AOP生成代理的原理图一起看,也就那么回事,只是丰富的许多属性了,我们会慢慢介绍的。

Spring AOP 使用范例

        项目结构

        分析 Spring AOP 源码的话,直接从最简单业务代码入手,一步步的对源码进行解析。希望借此能看清楚 Spring AOP 纵向和横向代码之间的联系,而且思维也不会太跳跃。下面就是 Spring AOP 测试程序 Test  项目的结构图:

        注:Spring 源码版本是 Spring-4.1.6,我的源码分析也是基于这一版本的,JDK 版本是 1.8,aspect 是用的 aspectjrt-1.7.4 和 aspectjweaver-1.7.4。

        创建用于拦截的Bean

        在实际项目中,Bean应该可以算是核心逻辑了,其中的 printTest 方法中可能会封装整个的核心业务逻辑,如此重要的地方我们想在printTest方法前后加入日志来进行跟踪或者调试也是很自然地想法,但是如果直接修改源码是不符合面向对象的设计原则的,它并不符合面向对象的设计方式,而且随意的改动原有的代码也会造成一定的风险,这里就体现 AOP 的优越性了。

package test;/*** 测试Bean** @Auther kay* @Date   2016-03-08*/
public class TestBean {private String testStr = "testStr";public String getTestStr(){return testStr;}public void setTestStr(String testStr){this.testStr = testStr;}public void printTest(){System.out.println("test Bean");}
}

        创建Advisor

        Spring AOP 实现的核心,这里采用了@AspectJ注释对POJO进行标注,使AOP的工作大大简化。

package test;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;/*** Aspect切面** @Auther kay* @Date   2016-03-08*/
@Aspect
public class AspectTest {/*** 配置切入点,主要为方便同类中其他方法使用此处配置的切入点*/private final String POINT_CUT = "execution(* test.TestBean.*(..))";/*** 配置前置通知,使用在方法aspect()上注册的切入点* 同时接受JoinPoint切入点对象,可以没有该参数*/@Before(POINT_CUT)public void beforeTest(){System.out.println("before Test");}/*** 配置后置通知,使用在方法aspect()上注册的切入点*/@After(POINT_CUT)public void afterTest(){System.out.println("after Test");}/*** 配置环绕通知,使用在方法aspect()上注册的切入点** @param point JoinPoint的支持接口* @return Object*/@Around(POINT_CUT)public Object arountTest(ProceedingJoinPoint point){System.out.println("before1");Object object = null;try{object = point.proceed();}catch (Throwable e){e.printStackTrace();}System.out.println("after1");return object;}
}

        配置文件

        XML是Spring的基础,尽管Spring一再简化配置,并且大有使用注解取代XML配置之势,但无论如何XML还是Spring的基石。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation=" http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.1.xsd"><!-- 激活自动代理功能 --><aop:aspectj-autoproxy /><!-- 业务逻辑切面配置 --><bean id="test" class = "test.TestBean" /><bean class="test.AspectTest" /></beans>

        测试

        测试程序,验证效果。

package test;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** 测试程序** @Auther kay* @Date   2016-03-08*/
public class Test {public static void main(String[] arge){ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");TestBean bean = context.getBean("test", TestBean.class);bean.printTest();}
}

        打印结果

        控制台打印如下代码:

        Spring AOP是如何实现AOP的?首先我们知道,Spring是否支持注释的AOP是由一个配置文件来控制的,也就是<aop:aspectj-autoproxy />,下面我们分析就从这句配置开始。

Spring AOP 的入口

        BeanDefinition 的解析

        首先spring-config.xml配置文件里的<aop:aspectj-autoproxy>进行解析,发现其如果不是bean标签,则会用不同的类来解析。解析AOP的是:http\://www.springframework.org/schema/aop=org.springframeworl.aop.config.AopNamespaceHandler。也就是 AopNamespaceHandler 类来解析,我们对 AopNamespaceHandler 类进行分析

        发现 AopNamespaceHandler 的一段代码是 <aop:aspectj-autoproxy> 解析的入口

AopNamespaceHandler.java

        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());

                

        BeanDefinition 的载入

        由此,我们知道只要配置文件中出现“aspectj-autoproxy”的注解时就会使用解析器对 AspectJAutoProxyBeanDefinitionParser 进行解析

        所有解析器,都是由 BeanDefinitionParser 接口的统一实现,入口都是从 parse函数开始的,AspectJAutoProxyBeanDefinitionParser 的 parse 函数如下:

AspectJAutoProxyBeanDefinitionParser .java

public BeanDefinition parse(Element element, ParserContext parserContext) {// 注册 AnnotationAwareAspectJAutoProxyCreatorAopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);// 对于注释中子类进行处理extendBeanDefinition(element, parserContext);return null;
}

        其中的 registerAspectJAnnotationAutoProxyCreatorIfNecessary 函数是 AnnotationAwareAspectJAutoProxyCreator 注册的地方,也是注册的主要逻辑实现的地方。

AopNamespaceUtils.java

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {// 注册或升级 AutoProxyCreator 定义 beanName 为 org.Springframework.aop.config.internalAutoProxyCreator的// BeanDefinitionBeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));// 对于 proxy-target-class 以及 expose-proxy 属性的处理useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);// 注册组件并通知,便于监听器作进一步处理// 其中 beanDefinition 的 className 为 AnnotationAwareAspectJAutoProxyCreatorregisterComponentIfNecessary(beanDefinition, parserContext);
}

        BeanDefinition 的注册

        在对于AOP实现上,基本上都是靠 AnnotationAwareAspectJAutoProxyCreator 去完成的,它可以根据@Point 注解定义的切点来自动代理相匹配的 bean。但是为了配置简便,Spring 使用了自定义配置来帮我们自动注册 AnnotationAwareAspectJAutoProxyCreator。具体实现如下

AopNamespaceUtils.java

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

AopConfigUtils.java

private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");// 如果已经存在自动代理创建器且存在的自动代理创建器与现在的不一致那么需要根据优先级来判断到底需要任何使用if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {// AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator"BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {// 改变bean 最重要的就是改变bean 所对应的 className 属性apcDefinition.setBeanClassName(cls.getName());}}// 如果已经存在自动代理创建器并且与将要创建的一致,那么无需再此创建return null;}RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// AUTO_PROXY_CREATOR_BEAN_NAME="org.springframework.aop.config.internalAutoProxyCreator"registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;
}

        以上代码中实现了自动注册 AnnotationAwareAspectJAutoProxyCreator 类的功能,同时这里还涉及了一个优先级的问题,如果已经存在了自动代理创建器,而且存在的自动代理创建器与现在的不一致,那么就需要根据优先级来判断到底需要使用哪一个?    

            

属性处理

        一般而言,Spring AOP 内部使用 JDK 动态代理或者 CGLIB 来为目标对象创建代理。如果被代理的目标对象实现了至少一个接口,则会使用 JDK 动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个 CGLIB 代理。一般情况下,使用 CGLIB 需要考虑增强(advise)Final 方法不能被复写以及需要指定 CGLIB 包的位置,尽管 CGLIB 效率更高,但还是推荐使用 JDK 动态代理。

        而 AOP 配置中的 prioxy-target-class 和 expose-proxy 属性在代理生成中起到了至关重要的。prioxy-target-class 主要负责上面两种代理的实现,而 expose-proxy 则负责自我调用切面中的增强。

AopNamespaceUtils.java

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {if (sourceElement != null) {// 对于 proxy-target-class 属性的处理boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));if (proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}// 对于 expose-proxy 属性的处理boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));if (exposeProxy) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}
}

AopConfigUtils.java

public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {// 强制使用,其实也是一个属性设置if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);}
}static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);}
}

        这些,基本就是Spring AOP部分的实现框架了,下节就要对AOP的主要实现类 AnnotationAwareAspectJAutoProxyCreator 进行分析。

http://www.lbrq.cn/news/2786023.html

相关文章:

  • 网站建设单位哪家好app推广方案
  • 女同性怎么做的视频网站域名关键词查询
  • 用asp.net制作一个网站需要多久seo业务培训
  • dedecms 一键更新网站seoapp推广
  • 西安 网站建设外包专业培训机构
  • seo网站设计工具网站发布
  • 帝国 只做网站地图广告代理公司
  • 做微网站的公司哪家好呢怎么出售友情链接
  • 怎么做好网站营销40个免费靠谱网站
  • 淄博网站优化平台推广策略都有哪些
  • 上海网站建设流网站建设公司地址在哪
  • 哪里有网站推广软件怎么找关键词
  • 顶岗实践网站开发东莞seo网络优化
  • 西宁软件优化网站建设app开发需要多少钱
  • 重庆免费推广网站怎样推广
  • 国外专门用于做网站图片的北京疫情消息1小时前
  • 沈阳建站seo检测优化
  • 青海省建设厅网站首页关键词优化公司
  • 帝国cms 网站例子谷歌建站
  • 做的网站怎么上传到网上运行win7优化大师官方免费下载
  • 一个wordpress多个网站网络优化主要做什么
  • 富利建设集团有限公司网站千锋教育培训机构就业率
  • 优化后的网站百度seo优化教程免费
  • 网站左右箭头素材成人大学报名官网入口
  • 网站建设需要哪些准备网络推广的方式
  • 佛山大良网站建设招聘百度网盘电脑版
  • 汉阴网站建设排行榜百度
  • 黄石做企业网站搜狐综合小时报2022113011
  • 有了域名后怎么完成网站建设广告投放是做什么的
  • 公司简介范文100字左右自建站seo如何做
  • (认识异常)
  • C++围绕音视频相关的资料都有哪些?如何进行学习
  • 【嵌入式电机控制#33】FOC:意法电控驱动层源码解析——整体框架篇(了解,常查阅)
  • Qt5.9.9 + Windows API 开发系统监控工具 - 教学级项目实战
  • Oracle:配置让插入语句时id自动输入
  • 【LeetCode】17. 电话号码的字母组合