SpringBoot加载流程

1. 开门见山

首先创建一个Application类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application .class, args);
    }
}

第一步就看到一个注解@SpringBootApplication,启动SpringBoot项目的必备。
我们打开这个注解类,可以看到里面还包含3个比较特殊的注解
在这里插入图片描述
@SpringBootConfiguration其实是一个@Configuration,@Configuration生命可以把额外的bean或者导入的注册到spring容器的上下文,就相当于xml中的,最常配合的就是对应类的方法上添加@Bean注解。
@EnableAutoConfiguration根据项目依赖自动化配置
@ComponentScan 组件扫描
@SpringBootApplication就是一个一拖三的功能组合,当然也可以单独使用上面三个注解。

2. SpringApplication

调用SpringApplication.run(ApiApplication.class, args)方法,就进入到SpringApplication的处理逻辑,最终返回一个ApplicationContext上下文.
在这里插入图片描述
new一个SpringApplication,在其构造函数里面有ApplicationContentInitializer和ApplicationListener的初始化操作.
在这里插入图片描述
ApplicationContextInitializer是Spring框架原有的概念, 这个类的主要目的就是在ConfigurableApplicationContext类型的ApplicationContext做refresh之前,允许我们对ConfigurableApplicationContext的实例做进一步的设置或者处理。

1.实现ApplicationContextInitializer
2.在SpringApplication中添加对应的实例
application.addInitializers(new ApplicationContextInitializerImpl());
3.或者通过factories中添加
context.initializer.classes=\
  xxx.ApplicationContextInitializerImpl

ApplicationListenter是配合ApplicationEvent的,实现ApplicationContext的事件机制.
主要事件有:
ApplicationFailedEvent:该事件在springboot启动失败是调用
ApplicationPreparedEvent:上下文context准备时触发
ApplicationReadyEvent:上下文已经准备完毕的时候触发
ApplicationStartedEvent:spring boot 启动监听类
SpringApplicationEvent:获取SpringApplication
ApplicationEnvironmentPreparedEvent:环境事先准备

也可以自定义事件:

1.事件源需要实现ApplicationEvent
2.listenter需要实现ApplicationListener,泛型对象就是上面定义的Event源

核心流程如下:

    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
  1. 第一步首先执行一个任务执行观察器
  2. 获取SpringApplicationRunListener集合
    SpringApplicationRunListener 可以监听springboot应用启动过程中的一些生命周期事件,并做一些处理.
public interface SpringApplicationRunListener {
    void starting();

    void environmentPrepared(ConfigurableEnvironment environment);

    void contextPrepared(ConfigurableApplicationContext context);

    void contextLoaded(ConfigurableApplicationContext context);

    void started(ConfigurableApplicationContext context);

    void running(ConfigurableApplicationContext context);

    void failed(ConfigurableApplicationContext context, Throwable exception);
}
private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
        return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }

2.1 SpringFactoriesLoader.loadFactoryNames方法
获取类路径下或者系统path路径的META-INF/spring.factories,解析出全部的类名
在这里插入图片描述
spring.factories是基于SPI的思想,实现一种解耦的方式.
在我们的日常应用中,org.springframework.boot.autoconfigure.EnableAutoConfiguration 自动配置基本是我们最常用的一种.

2.2 createSpringFactoriesInstances方法

Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                T instance = BeanUtils.instantiateClass(constructor, args);

根据对应的类加载器和获得的class全路径,实例化对应的bean.

2.3 启动监听器
springboot中默认的RunListenter是EventPublishingRunListener,事件广播.
在这里插入图片描述
封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听,启动监听.

public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }
  1. 环境准备
    默认情况下,如果情况下会实例化StandardServletEnvironment对象,然后把它绑定到SpringApplicationRunListeners上去.
  2. Banner
    默认是OFF,关闭的
  3. 初始化容器上下文
    部分代码省略
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
  1. 加载SpringBootExceptionReporter异常上报实例
  2. 上下文初始化
    将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联.
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  1. 上下文刷新
    调用AbstractApplicationContext.refresh()方法,刷新上下文.
    refresh()方法做了很多核心工作比如BeanFactory的设置,BeanFactoryPostProcessor接口的执行、BeanPostProcessor接口的执行、自动化配置类的解析、spring.factories的加载、bean的实例化等等.
 			this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } 
  1. 进行一些收尾工作,监听器的状态变化等等,最后返回创建的context上下文实例对象.
3. SPI

SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。

3.1 java spi
public interface SpiInterface {

    void print();
}
public class SpiImpl implements SpiInterface{
    @Override
    public void print() {
        System.out.println("print");
    }
}
public class SpiMain {

    public static void main(String[] args) {
        ServiceLoader<SpiInterface> load = ServiceLoader.load(SpiInterface.class);
        Iterator<SpiInterface> iterator = load.iterator();
        while(iterator.hasNext()) {
            SpiInterface next = iterator.next();
            next.print();
        }
    }
}

最后在resources里面添加META-INF.services/接口的全路径名文件,文件里面添加对应的接口实现类的全路径.
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210323142002858.p
java中的spi主要是依赖ServiceLoader,在使用的过程中实例的对象是懒加载的,通过迭代器的next()方法的时候会去实例化对应的接口实现.

迭代器

public Iterator<S> iterator() {
        return new Iterator<S>() {

            Iterator<Map.Entry<String,S>> knownProviders
                = providers.entrySet().iterator();

            public boolean hasNext() {
                if (knownProviders.hasNext())
                    return true;
                return lookupIterator.hasNext();
            }

            public S next() {
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                return lookupIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }

加载配置资源

			if (configs == null) {
                try {
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }

首先获取类对象,然后通过反射的方法实例化对应对象.
在这里插入图片描述

3.2 spring factories

Spring的SpringFactoriesLoader工厂的加载机制类似java提供的SPI机制一样,是Spring提供的一种加载方式。只需要在classpath路径下新建一个文件META-INF/spring.factories,并在里面按照Properties格式填写好接口和实现类即可通过SpringFactoriesLoader来实例化相应的Bean。其中key可以是接口、注解、或者抽象类的全限定名。value为相应的实现类的全限定名,当存在多个实现类时,用“,”进行分割,换行用""。
SpringFactoriesLoader的主要方法:

public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader);
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader)
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)
private static <T> T instantiateFactory(String instanceClassName, Class<T> factoryClass, ClassLoader classLoader)

更详细的代码请大家详细的看SpringFactoriesLoader.

加载spring factories的大致流程:
在这里插入图片描述

this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();

最后完成bean的实例化,以及刷新操作.

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值