Spring启动流程

Spring的启动流程

spring的启动过程其实就是其IoC容器的启动过程,对于web程序,IoC容器启动过程即是建立上下文的过程。

Spring项目的标准配置就是在web.xml文件中配置前端控制器与加载spring配置文件,初始化上下文

如果不指定配置文件位置,就会去找一个默认的文件位置,这个文件就是 /WEB-INF/springDispatcherServlet-servlet.xml 文件。如果不指定配置文件,可以在web应用下的WEB-INF下创建指定文件即可。

<!--前端控制器的配置-->
<servlet>

	<servlet-name>mvc-dispatcher</servlet-name>

	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

	<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

	<servlet-name>mvc-dispatcher</servlet-name>

	<url-pattern>/</url-pattern>

</servlet-mapping>
    
<!--配置文件指定与监听器配置-->
<context-param>

	<param-name>contextConfigLocation</param-name>

	<param-value>classpath*:/spring.xml</param-value>

</context-param>

<listener>   
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

ContextLoaderListener:初始化上下文的监听器,继承了contenxtLoader,实现了ServletContextListener接口

在启动项目时会触发contextInitialized方法(该方法主要完成ApplicationContext对象的创建),

在关闭项目时会触发contextDestroyed方法(该方法会执行ApplicationContext清理操作)

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    public ContextLoaderListener() {
    }

    public ContextLoaderListener(WebApplicationContext context) {
        super(context);
    }
	// 调用ContextLoader的initWebApplicationContext方法来初始化一个启动上下文WebApplicationContext
    public void contextInitialized(ServletContextEvent event) {
        this.initWebApplicationContext(event.getServletContext());
    }

    public void contextDestroyed(ServletContextEvent event) {
        this.closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}

this.initWebApplicationContext(event.getServletContext());:初始化应用上下文,bean的创建与建立

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    //初始化的根上下文保存在WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE这个属性里,如果不为空,说明已经初始化了
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
        throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");
    } else {
        servletContext.log("Initializing Spring root WebApplicationContext");
        Log logger = LogFactory.getLog(ContextLoader.class);
        if (logger.isInfoEnabled()) {
            logger.info("Root WebApplicationContext: initialization started");
        }

        long startTime = System.currentTimeMillis();

        try {
            // 如果为空就创建一个,启动的时候肯定为空,那么就执行创建方法
            if (this.context == null) {
                //(1)
                this.context = this.createWebApplicationContext(servletContext);
            }
            
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        ApplicationContext parent = this.loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
					//(2)
                    this.configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }
			// 将初始化的上下文信息放在WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性里面
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
            ClassLoader ccl = Thread.currentThread().getContextClassLoader();
            if (ccl == ContextLoader.class.getClassLoader()) {
                currentContext = this.context;
            } else if (ccl != null) {
                currentContextPerThread.put(ccl, this.context);
            }

            if (logger.isInfoEnabled()) {
                long elapsedTime = System.currentTimeMillis() - startTime;
                logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
            }

            return this.context;
        } catch (Error | RuntimeException var8) {
            logger.error("Context initialization failed", var8);
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
            throw var8;
        }
    }
}

(1)createWebApplicationContext:主要执行BeanUtils.instantiateClass(contextClass);方法,返回ConfigurableWebApplicationContext对象,然后执行this.context instanceof ConfigurableWebApplicationContext成立(2)

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
    // contextClass : "org.springframework.web.context.support.XmlWebApplicationContext"
    Class<?> contextClass = this.determineContextClass(sc);
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
    } else {
        // 实际上就是创建了一个XmlWebApplicationContext对象,因为是基于配置文件进行配置的
        return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
}


protected Class<?> determineContextClass(ServletContext servletContext) {
        String contextClassName = servletContext.getInitParameter("contextClass");
        if (contextClassName != null) {
            try {
                return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
            } catch (ClassNotFoundException var4) {
                throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", var4);
            }
        } else {
            // org.springframework.web.context.support.XmlWebApplicationContext
            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());

            try {
                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
            } catch (ClassNotFoundException var5) {
                throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", var5);
            }
        }
    }

(2)最重要是wac.refresh();方法。调用AbstractApplicationContext类中的refresh方法

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    String configLocationParam;
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        configLocationParam = sc.getInitParameter("contextId");
        if (configLocationParam != null) {
            wac.setId(configLocationParam);
        } else {
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
        }
    }

    wac.setServletContext(sc);
    configLocationParam = sc.getInitParameter("contextConfigLocation");
    if (configLocationParam != null) {
        wac.setConfigLocation(configLocationParam);
    }

    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
    }

    this.customizeContext(sc, wac);
    wac.refresh();
}


public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            // 1.调用容器准备刷新的方法,获取当前时间和同步标识
            this.prepareRefresh();

            // 2.调用子类的refreshBeanFactory()方法,Bean定义资源文件的载入从这里启动
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

            // 3.为beanFactory配置事件处理器、类加载器等
            this.prepareBeanFactory(beanFactory);

            try {
                // 4.为容器的某些子类指定特殊的Post事件处理器
                this.postProcessBeanFactory(beanFactory);

                // 5.调用所有注册的BeanFactoryPostProcesser的Bean
                this.invokeBeanFactoryPostProcessors(beanFactory);

                // 6.为BeanFactory注册Post事件处理器
                this.registerBeanPostProcessors(beanFactory);

                // 7.国际化初始化
                this.initMessageSource();

                // 8.初始化事件传播器
                this.initApplicationEventMulticaster();

                // 9.调用子类某些特殊的Bean初始化方法
                this.onRefresh();

                // 10.为上面的事件传播器注册事件监听器
                this.registerListeners();
                
                // 11.初始化所有单例Bean
                this.finishBeanFactoryInitialization(beanFactory);
                
                // 12.完成初始化
                this.finishRefresh();
            }

            catch (BeansException ex) {
                // 销毁已创建的Bean
                this.destroyBeans();
                // 取消刷新并重置标识
                this.cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

总结

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring启动过程可以分为以下几个步骤[^1]: 1. 创建Spring容器:通过创建一个ApplicationContext对象来启动Spring容器。可以使用不同的ApplicationContext实现类,如AnnotationConfigApplicationContext、ClassPathXmlApplicationContext等。 2. 解析配置类:如果使用AnnotationConfigApplicationContext启动容器,会解析配置类,将配置类中的Bean定义注册到容器中。 3. 准备启动:在容器准备启动之前,会执行一些准备工作,如初始化消息源、初始化事件广播器等。 4. 注册Bean后置处理器:在容器启动之前,会注册一些Bean后置处理器,用于在Bean实例化和初始化过程中进行一些额外的处理。 5. 初始化BeanFactory:在容器启动之前,会对BeanFactory进行一些初始化操作,如设置类加载器、设置Bean的后置处理器等。 6. 完成容器初始化:在容器启动之前,会完成BeanFactory的初始化工作,包括实例化和初始化所有的单例Bean。 7. 容器启动完成通知:在容器启动完成后,可以通过创建一个实现SmartLifecycle接口的类来监听容器启动完成的通知。 以下是一个示例代码,演示了Spring启动过程中的一些关键步骤: ```java import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.SmartLifecycle; import org.springframework.stereotype.Component; @Component public class Beanfinish implements SmartLifecycle { @Override public void start() { System.out.println("容器启动完成通知..."); } @Override public void stop() { } @Override public boolean isRunning() { return false; } @Override public boolean isAutoStartup() { return true; } } public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); context.start(); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值