Cynicism Cynicism
首页
  • 前端学习笔记

    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript
    • JS设计模式总结
    • 小程序笔记
  • 后端学习笔记

    • 《JavaWeb》
    • 《SSM》
    • 《瑞吉外卖》
    • 《Git》
    • 《SpringCloud》
    • 《黑马点评》
    • 《Spring原理》
    • 《JVM》
    • 《Java并发编程》
    • 《学成在线》
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试
  • 常见问题
  • 实用技巧
  • 友情链接
实习
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Cynicism

Java后端学习中的IKUN
首页
  • 前端学习笔记

    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript
    • JS设计模式总结
    • 小程序笔记
  • 后端学习笔记

    • 《JavaWeb》
    • 《SSM》
    • 《瑞吉外卖》
    • 《Git》
    • 《SpringCloud》
    • 《黑马点评》
    • 《Spring原理》
    • 《JVM》
    • 《Java并发编程》
    • 《学成在线》
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 面试
  • 常见问题
  • 实用技巧
  • 友情链接
实习
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Bean生命周期
  • AOP
    • 1. AnnotationAwareAspectJAutoProxyCreator
    • 2. Spring注册AnnotationAwareAspectJAutoProxyCreator
      • 2.1 AopNamespaceHandler
      • 2.2 AspectJAutoProxyBeanDefinitionParser
      • 2.3 AopNamespaceUtils
      • 2.4 AopConfigUtils
      • 2.5 proxy-target-class和expose-proxy属性
      • 2.6 registerComponentIfNecessary
    • 3. 小结
  • WEB
  • SpringBoot
  • 策略模式
  • 初始化IOC容器
  • 《Spring原理》
cynicism
2024-01-06
目录

AOP

提示

本篇用于记录Spring-AOP的源码解析,讲解AOP核心类:AnnotationAwareAspectJAutoProxyCreator类如何注册到Spring中,并解析到SpringIOC的

# 1. AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator实现了AOP逻辑

我们通过以下配置可以让Spring自动完成对AnnotationAwareAspectJAutoProxyCreator类的注册,从而实现AOP的功能。

<aop:aspectj-autoproxy/>
1

在讲解AnnotationAwareAspectJAutoProxyCreator功能之前,先得知道它是怎么被注册到Spring中,并如何被解析到SringIOC中的?下面来看看Spring是如何注册AnnotationAwareAspectJAutoProxyCreator这个类。

# 2. Spring注册AnnotationAwareAspectJAutoProxyCreator

说到Spring注册AnnotationAwareAspectJAutoProxyCreator,那要从SpringIOC加载META-INF/spring.handlers说起了。SpringIOC在初始化时,不仅从XML中获取了bean的定义信息,还从classpath下的META-INF/spring.handlers中获取到对应的Handler,可以从spring-aop的jar包中查看到该文件,文件内容如下:

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

# 2.1 AopNamespaceHandler

Springd通过DefaultNamepsaceHandlerResolver类的getHandlerMappings()方法上将配置文件中的xmlns配置都解析成了一个Java命名解析器(NamespaceHandler)

public class AopNamespaceHandler extends NamespaceHandlerSupport {
    public AopNamespaceHandler() {
    }
    public void init() {
        this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        // 1. 注册入口
        this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
        this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }
}
1
2
3
4
5
6
7
8
9
10
11

可以看到,在init()方法里,Spring对aspectj-autoproxy也就是AnnotationAwareAspectJAutoProxyCreator进行了注册

# 2.2 AspectJAutoProxyBeanDefinitionParser

调用AspectJAutoProxyBeanDefinitionParser类中的parse方法

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
   // 2. 解析入口为parse方法
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
		extendBeanDefinition(element, parserContext);
		return null;
	}
}
1
2
3
4
5
6
7
8

在Spring中,所有的解析器都是对BeanDefinitionParser接口的同一实现,解析入口都是从parse方法开始的

# 2.3 AopNamespaceUtils

调用类中的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法,获得BeanDefinition和一些配置信息

public abstract class AopNamespaceUtils {
    public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";
    private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";
    ...
    // 3. 获取BeanDefinition和一些配置信息
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
        //把应用了@Aspect注解修饰的bean注册成BeanDefinition
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        //处理proxy-target-class和expose-proxy属性
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        //注册组件并通知解析器
        registerComponentIfNecessary(beanDefinition, parserContext);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.4 AopConfigUtils

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法其实是调用了该类的registerOrEscalateApcAsRequired方法

public abstract class AopConfigUtils {

    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }

    @Nullable
    private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                int requiredPriority = findPriorityForClass(cls);
                if (currentPriority < requiredPriority) {
                    apcDefinition.setBeanClassName(cls.getName());
                }
            }

            return null;
        } else {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
            beanDefinition.setSource(source);
            beanDefinition.getPropertyValues().add("order", -2147483648);
            beanDefinition.setRole(2);
            registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
            return beanDefinition;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

registerOrEscalateApcAsRequired方法的作用就是获取AnnotationAwareAspectJAutoProxyCreator的BeanDefinition,然后根据优先级来装配这个BeanDefinition。

获取到了AnnotationAwareAspectJAutoProxyCreator之后,接下来就要将配置信息和BeanDefinition一起注册到SpringIOC中。

无图无真相,可以看到registerAspectJAnnotationAutoProxyCreatorIfNecessary方法返回的beanDefinition

# 2.5 proxy-target-class和expose-proxy属性

如果proxy-target-class和expose-proxy都为true时,代码的逻辑

public abstract class AopConfigUtils {
    ...
    /*
     * 如果proxy-target-class为true,则走该方法的逻辑
     */
    public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }

    }
    
    /*
     * 如果expose-proxy为true,则走该方法的逻辑
     */
    public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
            BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
        }

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

把bean的定义信息存放到了BeanDefinition中,Spring将设置的proxyTargetClass和exposeProxy的值存放到了BeanDefinition的PropertyValues里。

# 2.6 registerComponentIfNecessary

   //把应用了@Aspect注解修饰的bean注册成BeanDefinition
   BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
   //处理proxy-target-class和expose-proxy属性
   useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
   //注册组件并通知解析器
   registerComponentIfNecessary(beanDefinition, parserContext);
1
2
3
4
5
6

经过了useClassProxyingIfNecessary()方法的调用,ParserContext对象中存放好了注册的额外信息(proxy-target-class、expose-proxy值等),这里暂且将ParserContext称为解析上下文。

由上面的源码2.3节可知,在AopNamespaceUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中,将获取的org.springframework.aop.config.internalAutoProxyCreator的BeanDefinition和解析上下文一起传入registerComponentIfNecessary方法中,进行Component组件注册。

public abstract class AopNamespaceUtils {
    ...
    private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
        if (beanDefinition != null) {
            parserContext.registerComponent(new BeanComponentDefinition(beanDefinition, "org.springframework.aop.config.internalAutoProxyCreator"));
        }

    }
}
1
2
3
4
5
6
7
8
9

在随后的registerComponentIfNecessary方法中,经过new BeanComponentDefinition()构造方法的调用,已经将AnnotationAwareAspectJAutoProxyCreator的BeanDefinition注册到了SpringIOC中,存放在解析上下文(ParserContext)中。

解析上下文存放在SpringIOC(ApplicationContext,又称为Spring应用容器上下文)中

最后,在AspectJAutoProxyBeanDefinitionParser类的extendBeanDefinition方法中取出。

AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
1
2
private void extendBeanDefinition(Element element, ParserContext parserContext) {
		BeanDefinition beanDef =
				parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
		if (element.hasChildNodes()) {
			addIncludePatterns(element, parserContext, beanDef);
		}
	}
1
2
3
4
5
6
7

# 3. 小结

  1. aop:aspectj-autoproxy/的作用是在Spring中注册AnnotationAwareAspectJAutoProxyCreator
  2. 注册之后的解析工作是由AspectJAutoProxyBeanDefinitionParser类的.parse方法完成的
  3. aop:aspectj-autoproxy/的proxy-target-class和expose-proxy属性会被注册到BeanDefinition的PropertyValues里
  4. proxy-target-class的作用:
  • 强制使用CGLIB,配置如下属性即可使用CGLIB
<aop:config proxy-target-class="true"/>
1
  • 使用CGLIB代理和@AspectJ自动代理支持,配置如下配置即可实现
<aop:aspectj-autoproxy proxy-target-class="true"/>
1
  1. expose-proxy的作用:用于那种在在内部调用方法时无法调用切面逻辑的一种强制通知
编辑 (opens new window)
#spring
上次更新: 2025/05/12, 04:51:03
Bean生命周期
WEB

← Bean生命周期 WEB→

最近更新
01
JVM调优
06-03
02
Linux篇
03-30
03
Kafka篇
03-30
更多文章>
Theme by Vdoing | Copyright © 2023-2025 Cynicism | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式