Spring AOP

 这节介绍Spring AOP。关于Spring AOP的名字就不多做介绍了,网上有很多对AOP的解释。

1. 概念术语

1.1 切面(Aspect)

 切面是一个关注点的模块化,这个关注点可能是横切多个对象;

1.2 连接点(Join Point)

 连接点是指在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候;

1.3 通知(Advice)

 指在切面的某个特定的连接点上执行的动作。Spring切面可以应用5种通知:

  • 前置通知(Before):在目标方法或者说连接点被调用前执行的通知;

  • 后置通知(After):指在某个连接点完成后执行的通知;

  • 返回通知(After-returning):指在某个连接点成功执行之后执行的通知;

  • 异常通知(After-throwing):指在方法抛出异常后执行的通知;

  • 环绕通知(Around):指包围一个连接点通知,在被通知的方法调用之前和之后执行自定义的方法。

1.5 切点(Pointcut)

 指匹配连接点的断言。通知与一个切入点表达式关联,并在满足这个切入的连接点上运行,例如:当执行某个特定的名称的方法。

1.4 引入(Introduction)

 引入也被称为内部类型声明,声明额外的方法或者某个类型的字段。

1.5 目标对象(Target Object)

 目标对象是被一个或者多个切面所通知的对象。

1.6 AOP代理(AOP Proxy)

 AOP代理是指AOP框架创建的对象,用来实现切面(包括通知方法等功能)

1.7 织入(Wearving)

 指把切面连接到其他应用出程序类型或者对象上,并创建一个被通知的对象。或者说形成代理对象的方法的过程。

2. 入口

 AOP的一般配置如下:

file

 之前BeanDefiniton解析那节提到,XML的解析在classpath下META-INF的spring.handlers里。查看spring-aop模块可以看到如下配置

http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

 该处理类如下

file

 可以看到配置文件的处理交由

org.springframework.aop.config.ConfigBeanDefinitionParser

来处理,该类实现了BeanDefinitionParser接口,该接口的实现内容如下:

file

该方法主要完成两件事,

  • 注册AspectJAwareAdvisorAutoProxyCreator

  • 解析pointcut,advisor,aspect节点

 下面重点看下这两点

3. AspectJAwareAdvisorAutoProxyCreator

 AspectJAwareAdvisorAutoProxyCreator的继承结构如下:

file

该类在父类AbstractAutoProxyCreator那实现了接口SmartInstantiationAwareBeanPostProcessor,AbstractAutoProxyCreator主要实现了 方法

postProcessBeforeInstantiation

和方法

postProcessAfterInitialization

  postProcessBeforeInstantiation会在bean实例化前执行,如果返回非null,则不会实例化该bean。 postProcessAfterInitialization会在bean实例化并初始化后执行,如果返回非null,则使用该实例,否则使用原Bean对象。即对目标对象的包装可以发生在实例化前,也可以发生在初始化后。

3.1. postProcessBeforeInstantiation
file

 如上图示:

  • 在beanName为空或者目标类不包含该beanName的前提下,如果该bean是通知执行对象(advisedBeans)则不进行代理;如果为基础类且需要跳过则不进行代理,同时会将其标记为非通知执行对象。

  • 如果该beanName设置了TargetSource,则调用createProxy方法为该beanName创建代理对象,并将其进行标记,存于targetSourceBeans字段中。这里调用createProxy方法前会调用getAdvicesAndAdvisorsForBean方法获取该bean上设置的通知点。

3.2. postProcessAfterInitialization

 该方法主要调用了wrapIfNecessary,先判断初始化后的对象是否需要进行代理,如果需要进行代理,也是同上面一样调用createProxy方法,并调前前会调用getAdvicesAndAdvisorsForBean方法获取该bean上设置的通知点,如下:

file

该过程会将已经初始化后的bean包装为SingletonTargetSource传入。

3.3. getAdvicesAndAdvisorsForBean

 该方法的具体实现在其子类AbstractAdvisorAutoProxyCreator中,内容如下

file

主要调用了findEligibleAdvisors方法,如果该方法返回为空,则返回DO<u>  </u>NOT<u>  </u>PROXY.

 findEligibleAdvisors方法的处理流程为:

  • 找出所有实现了Advisors接口的Bean(配置为Advisor的Bean将会被包装为DefaultBeanFactoryPointcutAdvisor注册到Spring中;配置为Advice的将会被包装为AspectJPointcutAdvisor注册到Spring中)

  • 从所有Advisors中找出能够应用在beanClass上的bean,主要判断Advisors是否命中PointCut的规则

  • 根据Order对Advisor进行排序

3.4. createProxy
file

 如上为createProxy的主要内容,主要是使用相关的Advisor列表和TargetSource生成ProxyFactory对象,委托为ProxyFactory进行代理的包装。主要调用ProxyFacotry的getProxy方法, 该过程会在后面进行讲解.

4. 节点解析

 回到ConfigBeanDefinitionParser的parse过程,在注册完AspectJAwareAdvisorAutoProxyCreator后便是XML配置项的解析,主要包括:pointcut,advisor和aspect节点。

  • pointcut:为每个pointcut配置注册一个AspectJExpressionPointcut,范围为prototype的Bean,会设置expression属性
  • advisor:为每个advisor配置注册一个DefaultBeanFactoryPointcutAdvisor,需要关联一个advice,通过advice-ref指定对应的Bean;以及关联一个pointcut
  • aspect:包含一个或者多个advice节点已经pointcut节点,pointcut的解析同之前的类似,主要是advice节点。advice类别分为
    • before:执行前置通知
    • after:执行后置通知
    • after-returning:执行返回通知
    • after-throwing:执行异常通知
    • around:执行回环通知
      对于每个advice都会包装为一个AspectJPointcutAdvisor

5. ProxyFacotry

 ProxyFactory的结构如下:


file
  • ProxyFactory主要对ProxyCreatorSupport进行了封装,用于设置TargetSource和各拦截器接口。
  • ProxyCreatorSupport继承自AdvisedSupport,AdvisedSupport本身持有创建代理的各参数。同时引用了AopProxyFactory,将代理的创建动作委托给了AopProxyFactory。调用ProxyFactory的createAopProxy方法实际调用了AopProxyFactory的createAopProxy方法,该方法需要传入一个AdvisedSupport对象,即ProxyFactory本身。
  • DefaultAopProxyFactory决定使用哪种方式来创建代理,可选方式为Jdk动态代理或者Cglib,内容如下:


    file

6. aspectj-autoproxy

 aspectj-autoproxy提供自动完成创建代理织入切面的功能,能够通过配置注解Aspectj织入切面。aspectj-autoproxy 有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为true时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。根据上面的介绍,该动能由AspectJAutoProxyBeanDefinitionParser提供,主要向Spring注册了AnnotationAwareAspectJAutoProxyCreator类。

 AnnotationAwareAspectJAutoProxyCreator继承自AspectJAwareAdvisorAutoProxyCreator,只扩展了findCandidateAdvisors方法,将Advisor的搜索范围扩大到了注解上,使之可以用注解进行配置,具体委托给了BeanFactoryAspectJAdvisorsBuilderAdapter的BeanFactoryAspectJAdvisorsBuilderAdapter实现。

file

更多原创内容请搜索微信公众号:啊驼(doubaotaizi)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容