Tomcat 如何加载Spring?

1. Tomcat 提供的SCI 接口

 

SCIs 通过SPI 方式被注册和使用,tomcat要求所有MVC 框架必须包含 META-INF/services/javax.servlet.ServletContainerInitializer 文件,并且在里面指定自己的实现类。 

public interface ServletContainerInitializer {

    /**
     * Receives notification during startup of a web application of the classes
     * within the web application that matched the criteria defined via the
     * {@link javax.servlet.annotation.HandlesTypes} annotation.
     *
     * @param c     The (possibly null) set of classes that met the specified
     *              criteria
     * @param ctx   The ServletContext of the web application in which the
     *              classes were discovered
     *
     * @throws ServletException If an error occurs
     */
    void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}

2.  spring-mvc中SCIs 的实现类 (SpringServletContainerInitializer)

public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = Collections.emptyList();

		if (webAppInitializerClasses != null) {
			initializers = new ArrayList<>(webAppInitializerClasses.size());
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)
								ReflectionUtils.accessibleConstructor(waiClass).newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}

		servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
		AnnotationAwareOrderComparator.sort(initializers);
        // 执行所有 WebApplicationInitializer 的 onStartup 方法,完成应用的初始化
		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

3.  tomcat 启动SCIs (StandardContext.java)

protected synchronized void startInternal() throws LifecycleException {
            
           ....  
    
        // 调用所有的 ServletContainerInitializers 实现类
         for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
                initializers.entrySet()) {
                try {
                    entry.getKey().onStartup(entry.getValue(),
                            getServletContext());
                } catch (ServletException e) {
                    log.error(sm.getString("standardContext.sciFail"), e);
                    ok = false;
                    break;
                }
            }

            // 初始化并加载所有的 "load-on-startup" servlets
            if (ok) {
                if (!loadOnStartup(findChildren())){
                    log.error(sm.getString("standardContext.servletFail"));
                    ok = false;
                }
            }
            
        ....
}     

如果 DispatcherServlet 的 load-on-startup 小于0,会在首次处理请求时初始化,具体见第4步。

4.  tomcat 初始化并加载 DispatcherServlet (StandardWrapper.java)

StandardWrapper.allocate() -> loadServlet()

    public synchronized Servlet loadServlet() throws ServletException {


        Servlet servlet;
        try {
            long t1=System.currentTimeMillis();
            // Complain if no servlet class has been specified
            if (servletClass == null) {
                unavailable(null);
                throw new ServletException
                    (sm.getString("standardWrapper.notClass", getName()));
            }

            InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
            try {
                // 创建 DispatcherServlet 实例
                servlet = (Servlet) instanceManager.newInstance(servletClass);
            } catch (ClassCastException e) {
              
                throw new ServletException
                    (sm.getString("standardWrapper.notServlet", servletClass), e);
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
             
                throw new ServletException
                    (sm.getString("standardWrapper.instantiate", servletClass), e);
            }


            initServlet(servlet);

            fireContainerEvent("load", this);

            loadTime=System.currentTimeMillis() -t1;
        } finally {
            
        }
        return servlet;

}


如果觉得还不错的话,关注、分享、在看(关注不失联~), 原创不易,且看且珍惜~

posted on 2021-08-17 18:13  XuHe1  阅读(85)  评论(0编辑  收藏  举报