SpringBoot启动流程简析(三)

我们在上一节中说了SpringBoot的应用上下文的对象是AnnotationConfigEmbeddedWebApplicationContext,通过名字直译就是注解配置的可嵌入的web应用上下文。我们对它先不做过多的介绍,在不远的文章中我们就会对它进行一下简单的分析。

//上下文的一些准备动作
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
    ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
    ApplicationArguments applicationArguments, Banner printedBanner) {
    //将之前创建的环境变量的对象放入到应用上下文中
    context.setEnvironment(environment);
    //像Spring容器中先行注入BeanNameGenerator和ResourceLoader的实例
    postProcessApplicationContext(context);
    //调用之前在SpringBoot中加载的ApplicationContextInitializer的实现类,先进行一些初始化的动作
    //在之前的文章中我分析过在SpringBoot启动的过程中会从META-INF/spring.factories中加载ApplicationContextInitializer的对象
    applyInitializers(context);
    //这里是一个空实现
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    //// Add boot specific singleton beans
    //将之前得到的的应用参数解析器注入到Spring容器中
    context.getBeanFactory().registerSingleton("springApplicationArguments",
            applicationArguments);
    //将之前得到的的springBootBanner注入到Spring容器中
    if (printedBanner != null) {
        context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
    }
    // Load the sources
    // 加载sources 这里是指我们的启动类
    Set<Object> sources = getSources();
    //sources不能为空
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[sources.size()]));
    //监听上下文的变化
    listeners.contextLoaded(context);
}
load(context, sources.toArray(new Object[sources.size()]));
protected void load(ApplicationContext context, Object[] sources) {
    //创建BeanDefinition的加载器 直接new BeanDefinitionLoader
    BeanDefinitionLoader loader = createBeanDefinitionLoader(
    getBeanDefinitionRegistry(context), sources);
    //如果beanNameGenerator 对象不为空的话,则在BeanDefinitionLoader中set beanNameGenerator 
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    //如果resourceLoader 对象不为空的话,则在BeanDefinitionLoader中set resourceLoader 
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    //如果environment 对象不为空的话,则在BeanDefinitionLoader中set environment
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    //用BeanDefinitionLoader进行加载
    loader.load();
    }
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
    //由于AnnotationConfigEmbeddedWebApplicationContext实现了BeanDefinitionRegistry接口,所以这里直接返回AnnotationConfigEmbeddedWebApplicationContext的实例
    if (context instanceof BeanDefinitionRegistry) {
        return (BeanDefinitionRegistry) context;
    }
    //DefaultListableBeanFactory也实现了BeanDefinitionRegistry的接口
    if (context instanceof AbstractApplicationContext) {
        return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
                .getBeanFactory();
    }
    throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
public int load() {
    int count = 0;
    //这里的sources即是我们上面说的sources
    for (Object source : this.sources) {
        //load source
        count += load(source);
    }
    return count;
}
private int load(Object source) {
    Assert.notNull(source, "Source must not be null");
    //如果是Class类型 
    if (source instanceof Class<?>) {
        return load((Class<?>) source);
    }
    //如果是Resource类型
    if (source instanceof Resource) {
        return load((Resource) source);
    }
    if (source instanceof Package) {
        return load((Package) source);
    }
    if (source instanceof CharSequence) {
        return load((CharSequence) source);
    }
    //不是上面说的四种类型,则抛出异常
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
private int load(Class<?> source) {
    //如果是Groovy环境
    if (isGroovyPresent()) {
        // Any GroovyLoaders added in beans{} DSL can contribute beans here
        if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
                    GroovyBeanDefinitionSource.class);
            load(loader);
        }
    }
    //判断当前Class上面是否有Component注解
    if (isComponent(source)) {
        //将启动应用主类注入到Spring容器中 由于SpringBoot的自动配置的特性,所以这里在注入Spring容器的过程中会判断应不应该将这个类注入到Spring容器中
        this.annotatedReader.register(source);
        return 1;
    }
    return 0;
}
//这个方法的调用算是Spring容器开始启动工作了,这个过程是相当复杂我们以后会断断续续的分析点
refreshContext(context);

在这一篇文章中主要是分析了SpringBoot应用上下文的创建,和加载预先定义的几个Bean,像DefaultApplicationArguments、SpringBootBanner启动主类等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值