SpringBoot学习笔记——启动过程(三)

上两次我们通过分析SpringApplication的构造函数以及run函数的过程,大致了解了SpringBoot启动的流程。总的来说,SpirngBoot的启动其实还是ApplicationContext的初始化过程。
回想起我们上次提出的小问题,web服务器和我们的各种框架,实在什么时候加载进来的呢?首先,框架的加载比较简单,主要是通过配置Bean后处理器来实现的(这只是其中的一种方法),而web服务器,则是在refresh的时候,通过调用钩子函数onRefresh来实现的。

各种框架的加载

还记得我们在引入框架的时候,总会使用@EnableXXXX的注解吗?这个注解其实是一个组合注解,启到关键作用的,还是@Import注解。@Import注解可以导入一个配置类,我们需要引入的框架的相应的配置都是在这个配置类中完成的。具体的启动或者工作,可以在这个配置类中配置相应的Bean后处理器。

web服务器的启动

在ApplicationContext初始化的时候,运用了模板模式,给子代留用了一些回调函数,我们SpirngBoot的web服务器启动,就是在这些回调函数中完成的。下面我们将进行介绍。

ApplicationContext简单类图

在介绍这些能发挥我们各种配置功能的函数之前,我们首先需要先简单了解一下ApplicationContext的类图。(部分有删减)

输入图片说明

我们之前看到的相关的函数,包括run函数,都是在AbstractApplicationContext中的,但是这里预留了一个onRefresh的函数来供子类提供。

protected void onRefresh() throws BeansException {
    // For subclasses: do nothing by default.
}

而我们的AbstractApplicationContext的子代可以通过重写这样的钩子方法,来实现业务的扩充。

Web服务器的启动

这里是子类EmbeddedWebApplicationContext中对onRefresh函数的重写。其中tomcat的启动就是在这里完成的。

@Override
protected void onRefresh() {
    super.onRefresh();
    try {
        // 初始化并启动web容器
        createEmbeddedServletContainer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start embedded container", ex);
    }
}

Servlet和Filter的注册

既然web容器是在onRefresh中注册的,那么我们的Servlet和Filter是什么时候注册到web容器中的呢?结果你肯定猜得到,是在web容器启动完成之后的initializer函数来完成的,这里有一系列的初始化函数,在web容器启动的时候执行onStartup函数。

private void createEmbeddedServletContainer() {
    EmbeddedServletContainer localContainer = this.embeddedServletContainer;
    ServletContext localServletContext = getServletContext();
    //  如果localContainer和localServletContext 均为空的话,肯定是第一次启动的,就进行相关的配置工作
    if (localContainer == null && localServletContext == null) {
        // 获取到ServletContainer的对象生成工厂
        EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
        // 生成对应的ServletContainer,并且通过getSelfInitializer()获取到相应的初始化bean
        this.embeddedServletContainer = containerFactory
                .getEmbeddedServletContainer(getSelfInitializer());
    }
    else if (localServletContext != null) {
        // ...... 省略,主要是执行getSelfInitializer().onStartup()函数
    }
    // 配置初始化参数
    initPropertySources();
}

其中比较著名的初始化类,就是ServletRegistrationBean和FilterRegistrationBean啦,还记得我们之前那个可以获取到某个特定类的Bean的函数吗,他们分别在beanFactory中搜索Servlet和Filter类的bean,然后注册到tomcat的applicationContext中。

猜你喜欢

转载自my.oschina.net/nianshuo/blog/1785138