Spring基础系列-AOP源码分析

一、概述

Spring的两大特性:IOC和AOP。

AOP是面向切面编程,Spring内置了自己实现的基于动态代理技术的AOP,同时还支持成熟的AspectJ框架,我们这里主要讲述的还是内置的基于动态代理的AOP实现。因为面对一些普通的需求,Spring内置的AOP已经绰绰有余。

AOP一般用于增强原来的代码的功能,这种增强体现在辅助方面,比如安全、日志、事务等。

二、术语

1、连接点(JoinPoint)

连接点就是具体的代码中的切入点,指的是具体的一处代码位置。

2、切点(PointCut)

切点是对一系列代表同种功能(目的)的切入点(连接点)的统称,切点不是一个点,而是代表某一功能的一系列连接点的集合。

3、通知(Advice)

通知就是我们要在切点执行的操作,就是我们要实现的目的,是要实现的功能的代码实现。一般通知又称为增强,所谓增强就是对原来功能的基础上添加新功能,进行功能增强。

4、切面(Aspect)

切面是通知和切点的综合体,定义好了一个切面,那么我们就知道,这个AOP要实现的功能是什么,需要切入到程序中的那些地方。抽象层次中,切面是代码功能的横切面,这个横切面的位置就是切点、这个切面的功能就是通知。

5、织入(Weaving)

织入就是切面作用到目标代码中的方式,Spring内置的AOP采用的是动态代理的方式来织入,还可以采用编译器织入和加载期织入,后两者分别需要特定的编译器和类加载器来完成,后两种方式是AspectJ所支持的织入方式。

6、引介(Introduction)

引介是另一种类型的增强,它可以为类添加一些属性和方法。它和通知是并列的两种不同的增强。

7、目标对象(Target)

目标对象就是我们想要织入的对象,一般不会是一个,通常是一批符合条件的对象。

8、代理(Proxy)

代理就好理解了,Spring内置的AOP就是通过动态代理的方式实现织入的,创建目标对象的代理类,在代理类中执行通知的内容,然后在合适的位置调用目标对象的方法,来达到织入的目的。

三、Spring AOP概述

Spring AOP是基于动态代理技术实现的切面编程,代理技术包括JDK动态代理和CGLIB动态代理,前者基于接口实现,后者基于类实现。

1、Spring中使用AOP技术的方式:

1)定义切面类,使用@Aspect注解

2)在切面类中定义切点方法,使用@PointCut注解

3)在切面类中定义通知方法,使用@Before、@After、@Around等注解

4)在通知方法的注解中使用切点方法

5)在切面类上加设注解@Component

6)启动AOP功能,两种方式:原始的XML配置方式和注解方式

XMl方式:

注解方式:@EnableAspectJAutoProxy

配置方式:spring.auto.proxy=true

2、Spring AOP支持的增强类型

通知增强:Advice

前置通知:MethodBeforeAdvice-在连接点之前执行

后置通知:AfterReturningAdvice-在连接点正常执行完后执行,如果还未到连接点就异常,不会执行

环绕通知:AroundAdvice-在连接点前后执行

异常通知:AfterThrowingAdvice-在连接点抛出异常后执行

finally通知:AfterAdvice-最终执行,无论是否异常,方法执行结束都会执行

引介增强:IntroductionInterceptor->DelegatingIntroductionInterceptor

前五种很好理解,重点是最后一种引介增强,这种增强并不是针对方法的增强,而是针对类的增强,它会为目标添加属性和方法,比如它可以为目标类添加一个接口的实现。目标类原本没有实现某个接口,但是我们可以使用引介增强的方式为目标类创建一个实现该接口的代理,在这个代理中可以使用接口的功能来作用于目标对象。

3、原理图:(右键打开看大图)

Spring基础系列-AOP源码分析
四、源码分析

1、入口

1.1 入口一:

源码1-来自:AopNamespaceHandler

Spring基础系列-AOP源码分析
1 @Override
2 public void init() {
3 // In 2.0 XSD as well as in 2.1 XSD.
4 registerBeanDefinitionParser(“config”, new ConfigBeanDefinitionParser());
5 registerBeanDefinitionParser(“aspectj-autoproxy”, new AspectJAutoProxyBeanDefinitionParser());
6 registerBeanDefinitionDecorator(“scoped-proxy”, new ScopedProxyBeanDefinitionDecorator());
7
8 // Only in 2.0 XSD: moved to context namespace as of 2.1
9 registerBeanDefinitionParser(“spring-configured”, new SpringConfiguredBeanDefinitionParser());
10 }
Spring基础系列-AOP源码分析
上面源码就是针对XML配置中配置的解析,红色部分正是针对的解析,如果配置了aspectj-autoproxy,则注册Bean定义解析器:AspectJAutoProxyBeanDefinitionParser。

AspectJAutoProxyBeanDefinitionParser是一个实现了BeanDefinitionParser接口的类,专门用于解析切面自动代理的Bean定义的解析工作,重点在其parse方法。

源码2-来自:AspectJAutoProxyBeanDefinitionParser

Spring基础系列-AOP源码分析
1 class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
2
3 @Override
4 @Nullable
5 public BeanDefinition parse(Element element, ParserContext parserContext) {
6 // 1-注册AnnotationAwareAspectJAutoProxyCreator
7 AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
8 // 2-扩展BeanDefinition
9 extendBeanDefinition(element, parserContext);
10 return null;
11 }
12
13 private void extendBeanDefinition(Element element, ParserContext parserContext) {
14 // 获取BeanName为internalAutoProxyCreator的BeanDefinition,其实就是之前注册的自动代理构建器
15 BeanDefinition beanDef =
16 parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
17 if (element.hasChildNodes()) {
18 // 如果当前元素有子节点,则给上面获取的Bean定义添加子节点中明确定义的类型值(填充BeanDefinition)
19 addIncludePatterns(element, parserContext, beanDef);
20 }
21 }
22
23 private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
24 ManagedList includePatterns = new ManagedList<>();
25 NodeList childNodes = element.getChildNodes();//获取子节点
26 for (int i = 0; i < childNodes.getLength(); i++) {
27 // 遍历子节点,获取子节点中name属性值,封装到TypeStringValue中
28 // 在上下文中提取子节点includeElement的元数据保存到TypedStringValue的source属性中
29 // 最后封装好的TypeStringValue保存到includePatterns列表中
30 Node node = childNodes.item(i);
31 if (node instanceof Element) {
32 Element includeElement = (Element) node;
33 TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute(“name”));
34 valueHolder.setSource(parserContext.extractSource(includeElement));
35 includePatterns.add(valueHolder);
36 }
37 }
38 if (!includePatterns.isEmpty()) {
39 // 从解析上下文parserContext中提取指定节点element的元数据保存到includePatterns的source属性中,
40 // 然后将includePatterns保存到BeanDefinition的propertyValues属性中
41 includePatterns.setSource(parserContext.extractSource(element));
42 beanDef.getPropertyValues().add(“includePatterns”, includePatterns);
43 }
44 }
45
46 }
Spring基础系列-AOP源码分析
上面代码中有两个重点,首先就是registerAspectJAnnotationAutoProxyCreatorIfNecessary方法调用,用于注册AnnotationAwareAspectJAutoProxyCreator构建器;另一点就是在构建器注册完成后,为其填充一些必要内容,这些内容为XML配置中子节点的配置内容,具体内容参照源码,这里重点看看第一步,注册构建器的源码:

源码3-来自:AopNamespaceUtils

Spring基础系列-AOP源码分析
1 public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
2 ParserContext parserContext, Element sourceElement) {
3 // 1-注册或升级AnnotationAwareAspectJAutoProxyCreator
4 // parserContext.getRegistry()获取到的是BeanDefinitionRegistry注册器,第二个参数是提取的指定元素的元数据
5 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
6 parserContext.getRegistry(), parserContext.extractSource(sourceElement));
7 // 2-校验并设置是否适用基于CGLIB的动态代理实现AOP,和是否要暴露代理类
8 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
9 // 3-注册成组件
10 registerComponentIfNecessary(beanDefinition, parserContext);
11 }
12
13 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
14 if (sourceElement != null) {
15 boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));//获取XML中设置的proxy-target-class属性的值,解析为Boolean值
16 if (proxyTargetClass) {
17 // 如果为true,则强制自动代理构建器使用基于类的动态代理CGLIB,需要将属性设置到自动代理构建器的BeanDefinition中
18 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
19 }
20 boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));//获取XML中配置的expose-proxy属性的值,同样解析为Boolean值
21 if (exposeProxy) {
22 // 如果为true,强制自动代理构建器暴露代理类,需要将属性设置到自动代理构建器的BeanDefinition中
23 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
24 }
25 }
26 }
27
28 private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
29 if (beanDefinition != null) {
30 // 将自动代理构建器包装成为一个Bean组件定义。
31 // Bean组件定义是将一个BeanDefinition中包含的所有的属性的值(可能为一个BeanDefinition或者BeanReference)全部封装起来成为一个组件包,然后将其注册到解析上下文中
32 BeanComponentDefinition componentDefinition =
33 new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
34 parserContext.registerComponent(componentDefinition);
35 }
36 }
Spring基础系列-AOP源码分析
registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中主要做了三件事情:

1-注册构建器

2-配置属性

3-组件注册

针对第2和第3,在源码注释中解释的很清楚啦,主要看看第一步,继续进行构建器的注册:

源码4-来自:AopConfigUtils

Spring基础系列-AOP源码分析
1 public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
2 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
3 //如果构建器已经加载,获取其BeanDefinition,添加属性proxyTargetClass,值为true
4 BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
5 definition.getPropertyValues().add(“proxyTargetClass”, Boolean.TRUE);
6 }
7 }
8
9 public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
10 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
11 //如果构建器已经加载,获取其BeanDefinition,添加属性exposeProxy,值为true
12 BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
13 definition.getPropertyValues().add(“exposeProxy”, Boolean.TRUE);
14 }
15 }
16
17 @Nullable
18 private static BeanDefinition registerOrEscalateApcAsRequired(Class

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/z404739140/article/details/82590153
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞