从Springboot源码分析启动过程

从Springboot源码分析启动过程

这篇博客主要是通过Springboot的源码,分析Springboot项目的启动过程,深入理解spring的工作原理。其次,我对部分源码加上了注解,新手可以稍微看一下,同时我也希望大佬们能指出我理解有误的地方。

一、springboot启动源码解析

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();//项目计时器开始计时
    ConfigurableApplicationContext context = null;
    Collection exceptionReporters = new ArrayList<>();//异常处理类集合
    configureHeadlessProperty();//设置System全局参数
    SpringApplicationRunListeners listeners = getRunListeners(args);//SpringApplicationRunListener.class创建监视器实例
    listeners.starting();//发起starting事件(event)
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);//将启动参数转换成spring能解析的格式,例如:--foo=bar --foo="tom"
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        context = createApplicationContext();//根据webApplicationType的类型创建Context对象实例
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);//准备项目运行的环境,加载xml文件中配置的bean
        refreshContext(context);//更新Context 执行用户定义的postProcessBeanFactory操作,注册listener相关的bean,初始化所以剩下的单例类
        afterRefresh(context, applicationArguments);//用户自定义的操作
        stopWatch.stop();//项目计时器结束计时
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);//打印日志信息
        }
        listeners.started(context);//发起ApplicationStartedEvent事件
        callRunners(context, applicationArguments);//启动SpringApplication
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        listeners.running(context);//发起ApplicationReadyEvent事件
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

二、SpringApplication 类部分源码解析

/**
 * 准备项目运行时的环境变量
 * @param listeners 各种监听器
 * @param applicationArguments 参数对象
 * @return
 */
private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();//初始化environment的Properties和configuration
    configureEnvironment(environment, applicationArguments.getSourceArgs());//添加或替换commandLineArgs在environment中的属性值 确保profile被正确配置
    listeners.environmentPrepared(environment);//发起ApplicationEnvironmentPreparedEvent事件
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())
                .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

/**
 * 根据项目类型选择具体的环境参数类
 * @return
 */
private Class deduceEnvironmentClass() {
    switch (this.webApplicationType) {
    case SERVLET:
        return StandardServletEnvironment.class;
    case REACTIVE:
        return StandardReactiveWebEnvironment.class;
    default:
        return StandardEnvironment.class;
    }
}

/**
 * 初始化项目上下文环境,具体的初始化内容看参数命名就清楚了
 * @param context
 * @param environment
 * @param listeners
 * @param applicationArguments
 * @param printedBanner
 */
private void prepareContext(ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    context.setEnvironment(environment);
    postProcessApplicationContext(context);
    applyInitializers(context);
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
                .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // Load the sources
    Set sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
}

/**
 * 从spring的资源目录下加载factory对象的路径名,资源文件是META-INF/spring.factories
 * @param type
 * @param parameterTypes
 * @param args
 * @param 
 * @return
 */
private  Collection getSpringFactoriesInstances(Class type,
        Class[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));//从spring的资源目录下加载factory对象的路径名,资源文件是META-INF/spring.factories
    List instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

/**
 * 创建spring各种工厂对象实例 使用classLoader动态加载
 * @param type
 * @param parameterTypes
 * @param classLoader
 * @param args
 * @param names
 * @param 
 * @return
 */
@SuppressWarnings("unchecked")
private  List createSpringFactoriesInstances(Class type,
        Class[] parameterTypes, ClassLoader classLoader, Object[] args,
        Set names) {
    List instances = new ArrayList<>(names.size());
    for (String name : names) {
        try {
            Class instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);
            Constructor constructor = instanceClass
                    .getDeclaredConstructor(parameterTypes);//使用Constructor反射类调用有参构造函数创建实例
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            instances.add(instance);
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException(
                    "Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}

private ConfigurableEnvironment getOrCreateEnvironment() { //配置项目的环境属性,Note:在java自带的servlet context初始化之前
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
    case SERVLET:
        return new StandardServletEnvironment();
    case REACTIVE:
        return new StandardReactiveWebEnvironment();
    default:
        return new StandardEnvironment();
    }
}

protected void configureEnvironment(ConfigurableEnvironment environment,
        String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService
                .getSharedInstance();
        environment.setConversionService(
                (ConfigurableConversionService) conversionService);
    }
    configurePropertySources(environment, args);//添加或替换commandLineArgs在environment中的属性值
    configureProfiles(environment, args);//确保profile被正确配置
}

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug(
                "Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    BeanDefinitionLoader loader = createBeanDefinitionLoader(
            getBeanDefinitionRegistry(context), sources);//创建一个bean加载器,每个被加载的bean会被自动注册到cache中
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    loader.load();
}
 
 

以后我会根据启动过程和你们一起慢慢的解析spring的各种相关的源码,有机会的话实现一个@EnableXXXX注解,已经实现但是有bug

你可能感兴趣的:(从Springboot源码分析启动过程)