十、SpringBoot启动-刷新应用上下文前的准备

1.刷新应用上下文的准备

this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
	1.上文初始化了context,这里说的准备工作就相当于给context里面的属性进行设置;
	2.完成一些bean对象的创建;
我们自己写的核心启动类bean对象的创建也在prepareContext这个方法里完成。

在这里插入图片描述

1.1.设置应用上下的属性

1.1.1.设置environment

context.setEnvironment(environment);
设置容器环境

1.1.2.postProcessApplicationContext

postProcessApplicationContext(context);
执行容器后置处理

在这里插入图片描述

上一篇文章说到,在初始化应用上下文时调用BeanUtils.instantiateClass(contextClass),就已经创建了IOC容器对象;
context.getBeanFactory()就是获取容器对象,那么setConversionService就是给IOC容器设置转换服务(转换器);
转换器:比如我们在容器中可以把一些整数的字符串转换为整形。

1.1.3.applyInitializers

applyInitializers(context);
应用初始化器。

在这里插入图片描述····getInitializers()获取到初始化器(执行run方法钱准备阶段,在SpringApplication的构造方法里,准备的初始化器),遍历启动执行(initializer.initialize(context))。

1.1.4.listeners.contextPrepared(context);

向各个监听器发送容器已经准备好的事件

在这里插入图片描述····遍历监听器,将context发送给监听器。

完成了前三步,应用上下文的设置基本完成了,就发送给各个监听器。
这些监听器是SpringApplicationRunListeners类型的,根据之前的分析可以知道,
这个listeners只有一个值,就是EventPublishingRunListener(启动监听器)。

1.2.创建需要的bean对象

ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

1.2.1.封装args

beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
这个applicationArguments,就是我们传入的main方法的args(命令行参数)

在这里插入图片描述····将main方法的args参数封装成单例bean,注册进IOC容器。

1.2.2.封装banner

如果printedBanner不为空,那么也会被封装成单例bean;
这里我没有设置banner.txt,所以为null。

在这里插入图片描述

1.2.3.设置允许bean的定义信息被覆盖

判断这个beanFactory是不是DefaultListableBeanFactory类型;
如果是,就设置允许bean的定义信息被覆盖;
显然,之前已经知道这个IOC(beanFactory)容器就是DefaultListableBeanFactory类型的。

在这里插入图片描述

1.2.4.判断当前是否是懒加载

如果是就设置LazyInitializationBeanFactoryPostProcessor

在这里插入图片描述

1.3.获取资源并加载启动类

1.3.1.获取source

Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");

在这里插入图片描述····source是我们的启动类

1.3.2.将启动类注入容器

this.load(context, sources.toArray(new Object[0]));
sources是一个集合,取出我们的启动类。
load方法,通过核心启动类的字节码,生成实例对象,设置到IOC容器中。

在这里插入图片描述在这里插入图片描述

  • createBeanDefinitionLoader:方法两个参数;
  • this.getBeanDefinitionRegistry(context);
  • sources;

在这里插入图片描述所以将context向上造型成BeanDefinitionRegistry;

Spring容器在启动的时候,会先将类解析成BeanDefinition对象
然后将BeanDefinition存到DefaultListableBeanFactory里面的一个map中

在这里插入图片描述再看看这个BeanDefinitionLoader的构造方法
在这里插入图片描述

  • annotatedReader:注解形式的Bean定义读取器(Component等)。
  • xmlReader:xml配置形式的Bean定义读取器;
  • scanner:类路径扫描Bean定义读取器;
  • addExcludeFilter:扫描器添加排除过滤器。

经过前面步骤,loader(BeanDefinitionLoader)对象被创建出来了。
loader再调用load方法
在这里插入图片描述
又调用load方法在这里插入图片描述再调用load方法
在这里插入图片描述

isComponent判断source启动类上面有没有Component注解;
很明显是有,那么就使用注解形式的bean定义读取器,将启动类的BeanDefinition注册进beanDefinitionMap。

在这里插入图片描述
这个componentClasses是传入的启动类resource。

在这里插入图片描述在这个doRegisterBean方法里面,创建并设置AnnotatedGenericBeanDefinition的属性,当然是启动类相关的。

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) {
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            abd.setInstanceSupplier(supplier);
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
            abd.setScope(scopeMetadata.getScopeName());
            String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry);
            AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
            int var10;
            int var11;
            if (qualifiers != null) {
                Class[] var9 = qualifiers;
                var10 = qualifiers.length;

                for(var11 = 0; var11 < var10; ++var11) {
                    Class<? extends Annotation> qualifier = var9[var11];
                    if (Primary.class == qualifier) {
                        abd.setPrimary(true);
                    } else if (Lazy.class == qualifier) {
                        abd.setLazyInit(true);
                    } else {
                        abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                    }
                }
            }

            if (customizers != null) {
                BeanDefinitionCustomizer[] var13 = customizers;
                var10 = customizers.length;

                for(var11 = 0; var11 < var10; ++var11) {
                    BeanDefinitionCustomizer customizer = var13[var11];
                    customizer.customize(abd);
                }
            }

            BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
            definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
            BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
        }
    }

····设置这个beanDefinition的scop和beanName,然后通过AnnotatedGenericBeanDefinition和beanName构建一个beandefinition的持有对象。
····registerBeanDefinition看下图:
在这里插入图片描述····这里又调用registerBeanDefinition方法,这里调用的具体实现时DefaulListableBeanDefinition的实现,传递的参数时beanName和BeanDefinition

在这里插入图片描述在这里插入图片描述····在DefaultListableBeanFactory的registerBeanDefinition方法中,将beanName和beanDefinition分别作为key、value添加到beanDefinitionMap中。

核心启动类存入了beanDefinitionMap,并且在之前将这个beanDefinition设置成了singleton;
那么之后会从beanDefinitionMap中取出beanDefinition;
beanDefinition里面又存有启动类的Class字节码;
通过反射可以实例出对象,然后存到DefaultListableBeanFactory的单例池中;
单例池就是这个ConcurrentHashMap,这个singletonBeanNamesByType。

在这里插入图片描述

1.4.发布容器加载事件

启动类添加到了beanDefinitionMap;
那么刷新应用上下文的准备工作就只剩最后一步;
listeners.contextLoaded(context);

1.5.观察context

刷新应用上下文前的准备工作做完之后,我们看看context的属性值

在这里插入图片描述在这里插入图片描述

····其实从这里也可以看出来,启动类只是添加到了beanDefinitionMap里面,还没有生成实例注入到单例池里面。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值