SpringIOC源码解析(基于注解)

缺乏、安全感 2024-04-18 20:38 217阅读 0赞

注意,看完这篇文章需要很长很长很长时间。。。

准备工作

本文会基于注解的方向分析SpringIOC模块的整体流程,在阅读本篇文章之前建议您先阅读基于XML分析的两篇文章: SpringIOC源码解析(上),SpringIOC源码解析(下)

Demo工程

本次源码分析的demo工程我已经准备好了,大家可自行前往以下地址下载








  1. 1
  1. https://github.com/shiyujun/spring-framework

本次工程复用了之前工程的包cn.shiyujun.service中的接口和实现类,同时新增了一个基于注解的配置类,此类在cn.shiyujun.config包下








  1. 1
    2
    3
    4
    5
    6
    7
  1. @Configuration
    public class AnnotationConfig {

    @Bean
    public IOCService iocService(){

    return new IOCServiceImpl();
    }
    }

然后就是启动类了,启动类在cn.shiyujun.demo包下








  1. 1
    2
    3
    4
    5
    6
    7
  1. public class AnnotationIOCDemo {

    public static void main (String args[]){

    ApplicationContext context = new AnnotationConfigApplicationContext(cn.shiyujun.config);
    IOCService iocService=context.getBean(IOCService.class);
    System.out.println(iocService.hollo());
    }
    }

AnnotationConfigApplicationContext继承关系

640?wx\_fmt=png

再次拿出之前的一张图片,可以看到相较于ClassPathXmlApplicationContextFileSystemXmlApplicationContext来说AnnotationConfigApplicationContext这个类的辈分好像更高一些

接着我们看一下它的方法

640?wx\_fmt=png

我们会发现除了register注册bean的方法以外,有一个scan方法,有没有感觉很熟悉。@CompantScan用过没,他们之间什么关系,在启动类中new AnnotationConfigApplicationContext的时候传的一个包名是不是跟这个有关系?带着疑问往下看吧

源码分析

构造方法

源码分析第一站就是进入如下构造方法








  1. 1
    2
    3
    4
    5
  1. public AnnotationConfigApplicationContext(String basePackages) {

    this();
    scan(basePackages);
    refresh();
    }

千万不要小瞧上方简简单单的三行代码,我们整篇文章都会基于这三行代码来展开

首先看this








  1. 1
    2
    3
    4
    5
    6
  1. public AnnotationConfigApplicationContext() {

    //注解bean读取器
    this.reader = new AnnotatedBeanDefinitionReader(this);
    //注解bean扫描器
    this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

同时子类的构造方法执行之前肯定会先执行父类的构造方法,所以还有父类
GenericApplicationContext的构造方法








  1. 1
    2
    3
    4
  1. public GenericApplicationContext() {      
    //这个bean的相关知识请参考之前的文章
    this.beanFactory = new DefaultListableBeanFactory();
    }
注册bean

接着看scan方法








  1. 1
    2
    3
    4
  1. public void scan(String basePackages) {

    Assert.notEmpty(basePackages, At least one base package must be specified);
    this.scanner.scan(basePackages);
    }

可以看到这里调用的是bean扫描器ClassPathBeanDefinitionScannerscan方法








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  1. public int scan(String basePackages) {

    //获取当前注册bean的数量
    int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
    //往下看
    doScan(basePackages);

    if (this.includeAnnotationConfig) {

    //注册配置处理器
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    }
    //返回此次注册的数量
    return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

接着往下看doScan方法








  1. 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
  1. protected Set<BeanDefinitionHolder> doScan(String basePackages) {

    Assert.notEmpty(basePackages, At least one base package must be specified);
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    //遍历需要扫描的包路径
    for (String basePackage : basePackages) {

    //先跟进去看,下面的方法先忽略
    Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    for (BeanDefinition candidate : candidates) {

    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    candidate.setScope(scopeMetadata.getScopeName());
    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    if (candidate instanceof AbstractBeanDefinition) {

    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    }
    if (candidate instanceof AnnotatedBeanDefinition) {

    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    }
    if (checkCandidate(beanName, candidate)) {

    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    definitionHolder =
    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    beanDefinitions.add(definitionHolder);
    registerBeanDefinition(definitionHolder, this.registry);
    }
    }
    }
    return beanDefinitions;
    }
扫描包







  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10

  1. public Set<BeanDefinition> findCandidateComponents(String basePackage) {

    //判断是否使用Filter指定忽略包不扫描
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {

    return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {

    //扫描包
    return scanCandidateComponents(basePackage);
    }

在接着往下看之前,我们有必要先认识一个东东,MetadataReader。这个接口有三个方法








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
  1. public interface MetadataReader {


    Resource getResource();

    ClassMetadata getClassMetadata();

    AnnotationMetadata getAnnotationMetadata();

    }

第一个返回Resource就不必多说了,就是配置类的资源对象。第二个第三个根据名字我们可以猜到是类的元数据和注解的元数据
可以看一下它们两个的方法

640?wx\_fmt=png

640?wx\_fmt=png

接着往下看








  1. 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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
  1. private Set<BeanDefinition> scanCandidateComponents(String basePackage) {

    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {

    //组装扫描路径(组装完成后是这种格式:classpath:cn/shiyujun/config/**/.class)
    String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
    resolveBasePackage(basePackage) + ‘/‘ + this.resourcePattern;
    //根据路径获取资源对象
    Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
    boolean traceEnabled = logger.isTraceEnabled();
    boolean debugEnabled = logger.isDebugEnabled();
    for (Resource resource : resources) {

    if (traceEnabled) {

    logger.trace(Scanning + resource);
    }
    if (resource.isReadable()) {

    try {

    //根据资源对象通过反射获取资源对象的MetadataReader,具体就不展开说了
    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
    //查看配置类是否有@Conditional一系列的注解,然后是否满足注册Bean的条件,关于这个知识点可以参考我之前的文章:https://mp.weixin.qq.com/s/RXYIh_g5iU1e3liK-8n5zA
    if (isCandidateComponent(metadataReader)) {

    ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    sbd.setResource(resource);
    sbd.setSource(resource);
    if (isCandidateComponent(sbd)) {

    if (debugEnabled) {

    logger.debug(Identified candidate component class: + resource);
    }
    candidates.add(sbd);
    }
    else {

    if (debugEnabled) {

    logger.debug(Ignored because not a concrete top-level class: + resource);
    }
    }
    }
    else {

    if (traceEnabled) {

    logger.trace(Ignored because not matching any filter: + resource);
    }
    }
    }
    catch (Throwable ex) {

    throw new BeanDefinitionStoreException(
    Failed to read candidate component class: + resource, ex);
    }
    }
    else {

    if (traceEnabled) {

    logger.trace(Ignored because not readable: + resource);
    }
    }
    }
    }
    catch (IOException ex) {

    throw new BeanDefinitionStoreException(I/O failure during classpath scanning, ex);
    }
    return candidates;
    }
创建BeanDefinition

现在回到开始的doScan方法








  1. 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
    33
    34
    35
  1. protected Set<BeanDefinitionHolder> doScan(String basePackages) {

    Assert.notEmpty(basePackages, At least one base package must be specified);
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    //遍历需要扫描的包路径
    for (String basePackage : basePackages) {

    //获取所有符合条件的BeanDefinition
    Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    for (BeanDefinition candidate : candidates) {

    //绑定BeanDefinition与Scope
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    candidate.setScope(scopeMetadata.getScopeName());
    //查看是否配置类是否指定bean的名称,如没指定则使用类名首字母小写
    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    //下面两个if是处理lazy、Autowire、DependencyOn、initMethod、enforceInitMethod、destroyMethod、enforceDestroyMethod、Primary、Role、Description这些逻辑的
    if (candidate instanceof AbstractBeanDefinition) {

    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    }
    if (candidate instanceof AnnotatedBeanDefinition) {

    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    }
    //检查bean是否存在
    if (checkCandidate(beanName, candidate)) {

    //又包装了一层
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    //检查scope是否创建,如未创建则进行创建
    definitionHolder =
    AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    beanDefinitions.add(definitionHolder);
    //重点来了,往下看
    registerBeanDefinition(definitionHolder, this.registry);
    }
    }
    }
    return beanDefinitions;
    }
注册bean

到了一个比较重要的节点了,跟着上文的registerBeanDefinition方法走








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
  1. protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {

    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }

    public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {



    String beanName = definitionHolder.getBeanName();
    // 注册bean,往下看
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    //如果存在别名则循环注册别名,逻辑跟上方差不多,就不展开了
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {

    for (String alias: aliases) {

    registry.registerAlias(beanName, alias);
    }
    }
    }

其实这个注册bean的方法是DefaultListableBeanFactory的方法,之前的文章已经解析过了,大体就是下面这么个流程








  1. 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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
  1. @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {


    Assert.hasText(beanName, Bean name must not be empty);
    Assert.notNull(beanDefinition, BeanDefinition must not be null);

    if (beanDefinition instanceof AbstractBeanDefinition) {

    try {

    ((AbstractBeanDefinition) beanDefinition).validate();
    }
    catch (BeanDefinitionValidationException ex) {

    throw new BeanDefinitionStoreException(…);
    }
    }

    BeanDefinition oldBeanDefinition;

    // 所有的 Bean 注册后都会被放入到这个beanDefinitionMap 中,查看是否已存在这个bean
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);

    // 处理重复名称的 Bean 定义的情况
    if (oldBeanDefinition != null) {

    if (!isAllowBeanDefinitionOverriding()) {

    // 如果不允许覆盖的话,抛异常
    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    Cannot register bean definition [“ + beanDefinition + “] for bean ‘“ + beanName +
    “‘: There is already [“ + oldBeanDefinition + “] bound.”);
    }
    else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {

    // 用框架定义的 Bean 覆盖用户自定义的 Bean
    if (this.logger.isWarnEnabled()) {

    this.logger.warn(Overriding user-defined bean definition for bean ‘“ + beanName +
    “‘ with a framework-generated bean definition: replacing [“ +
    oldBeanDefinition + “] with [“ + beanDefinition + “]”);
    }
    }
    else if (!beanDefinition.equals(oldBeanDefinition)) {

    // 用新的 Bean 覆盖旧的 Bean
    if (this.logger.isWarnEnabled()) {

    this.logger.warn(Overriding user-defined bean definition for bean ‘“ + beanName +
    “‘ with a framework-generated bean definition: replacing [“ +
    oldBeanDefinition + “] with [“ + beanDefinition + “]”);
    }
    }
    else {

    // log…用同等的 Bean 覆盖旧的 Bean
    if (this.logger.isInfoEnabled()) {

    this.logger.info(Overriding bean definition for bean ‘“ + beanName +
    “‘ with a different definition: replacing [“ + oldBeanDefinition +
    “] with [“ + beanDefinition + “]”);
    }
    }
    // 覆盖
    this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {

    // 判断是否已经有其他的 Bean 开始初始化了.注意,“注册Bean” 这个动作结束,Bean 依然还没有初始化 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
    if (hasBeanCreationStarted()) {

    // Cannot modify startup-time collection elements anymore (for stable iteration)
    synchronized (this.beanDefinitionMap) {

    this.beanDefinitionMap.put(beanName, beanDefinition);
    List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
    updatedDefinitions.addAll(this.beanDefinitionNames);
    updatedDefinitions.add(beanName);
    this.beanDefinitionNames = updatedDefinitions;
    if (this.manualSingletonNames.contains(beanName)) {

    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
    updatedSingletons.remove(beanName);
    this.manualSingletonNames = updatedSingletons;
    }
    }
    }
    else {



    // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
    this.beanDefinitionMap.put(beanName, beanDefinition);
    // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
    this.beanDefinitionNames.add(beanName);
    // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
    this.manualSingletonNames.remove(beanName);
    }
    this.frozenBeanDefinitionNames = null;
    }

    if (oldBeanDefinition != null || containsSingleton(beanName)) {

    resetBeanDefinition(beanName);
    }
    }

现在回到文章开始的三句代码








  1. 1
    2
    3
    4
    5
  1. public AnnotationConfigApplicationContext(String basePackages) {

    this();
    scan(basePackages);
    refresh();
    }

可以看到,只剩最后一个refresh()方法了,如果看过之前文章的同学可能都已经知道这里面是什么东西了

refresh()

首先整个方法进来以后跟使用XML的时候是一样的








  1. 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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
  1. public void refresh() throws BeansException, IllegalStateException {


    synchronized (this.startupShutdownMonitor) {


    // 记录容器的启动时间、标记“已启动”状态、检查环境变量
    prepareRefresh();

    // 初始化BeanFactory容器、注册BeanDefinition
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
    prepareBeanFactory(beanFactory);

    try {

    // 扩展点
    postProcessBeanFactory(beanFactory);
    // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法
    invokeBeanFactoryPostProcessors(beanFactory);

    // 注册 BeanPostProcessor 的实现类
    registerBeanPostProcessors(beanFactory);

    // 初始化MessageSource
    initMessageSource();

    // 初始化事件广播器
    initApplicationEventMulticaster();

    // 扩展点
    onRefresh();

    // 注册事件监听器
    registerListeners();


    // 初始化所有的 singleton beans
    finishBeanFactoryInitialization(beanFactory);

    // 广播事件
    finishRefresh();
    }

    catch (BeansException ex) {

    if (logger.isWarnEnabled()) {

    logger.warn(Exception encountered during context initialization - +
    cancelling refresh attempt: + ex);
    }

    // 销毁已经初始化的的Bean
    destroyBeans();

    // 设置 ‘active’ 状态
    cancelRefresh(ex);

    throw ex;
    }

    finally {

    // 清除缓存
    resetCommonCaches();
    }
    }
    }
与XML的不同点

obtainFreshBeanFactory()方法
还记得在之前的文章中列出了好几万行代码来解析这个方法,但是回忆一个这个方法是干啥的来着,创建bean容器,但是呢,bean容器在scan方法里就已经创建好了,所以这里就没必要再进行额外的逻辑了,你看现在它的代码现在多简单








  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {

    logger.debug(Bean factory for + getDisplayName() + “: + beanFactory);
    }
    return beanFactory;
    }
    protected final void refreshBeanFactory() throws IllegalStateException {

    if (!this.refreshed.compareAndSet(false, true)) {

    throw new IllegalStateException(
    GenericApplicationContext does not support multiple refresh attempts: just call refresh once);
    }
    this.beanFactory.setSerializationId(getId());
    }

再接下来,其实就没了,有一个重点就是初始化,但是初始化逻辑是放在这个Spring家族的超级富二代DefaultListableBeanFactory身上的。

心得体会

源码阅读入门很难,面对几十兆几百兆的代码不是一时半会就能看明白的,也不是一遍两遍debug就能搞懂的。阅读源码,一定要静下心来花上几个小时甚至几天的时间来钻研。

一通百通,当你研究明白一部分以后,再去看另外的部分,就好像有人推着你走一样,无比的顺利

640?wx\_fmt=gif

不得不看

1.SpringCloud系列博客汇总

2.为啥一线大厂面试必问Redis,有啥好问的?

3.Java多线程面试必备基础知识汇总

4.Java集合源码分析汇总

5.Linux常用命令汇总

6.JVM系列文章汇总

7.MySQL系列文章汇总

8.RabbitMQ系列文章汇总

640?wx\_fmt=jpeg

发表评论

表情:
评论列表 (有 0 条评论,217人围观)

还没有评论,来说两句吧...

相关阅读