• Spring2.3.1外部servlet容器启动配置原理


    根据servlet3.0规范:
    规则:
    1)、服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例:
    2)、ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为
    javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名
    3)、还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类;

     可以找到全类名为

    org.springframework.web.SpringServletContainerInitializer

    进入这个类
    //这个注解说明了会加载WebApplicationInitializer这个类
    @HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { /** * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer} * implementations present on the application classpath. * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)}, * Servlet 3.0+ containers will automatically scan the classpath for implementations * of Spring's {@code WebApplicationInitializer} interface and provide the set of all * such types to the {@code webAppInitializerClasses} parameter of this method. * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath, * this method is effectively a no-op. An INFO-level log message will be issued notifying * the user that the {@code ServletContainerInitializer} has indeed been invoked but that * no {@code WebApplicationInitializer} implementations were found. * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected, * they will be instantiated (and <em>sorted</em> if the @{@link * org.springframework.core.annotation.Order @Order} annotation is present or * the {@link org.springframework.core.Ordered Ordered} interface has been * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)} * method will be invoked on each instance, delegating the {@code ServletContext} such * that each instance may register and configure servlets such as Spring's * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener}, * or any other Servlet API componentry such as filters. * @param webAppInitializerClasses all implementations of * {@link WebApplicationInitializer} found on the application classpath * @param servletContext the servlet context to be initialized * @see WebApplicationInitializer#onStartup(ServletContext) * @see AnnotationAwareOrderComparator */ @Override public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { List<WebApplicationInitializer> initializers = new LinkedList<>(); if (webAppInitializerClasses != null) { 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); for (WebApplicationInitializer initializer : initializers) {
    //执行每一个WebApplicationInitializer的onStartUp方法 initializer.onStartup(servletContext); } } }

    而我们的类

    public class ServletInitializer extends SpringBootServletInitializer {
    
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
            return application.sources(DemoApplication.class);
        }
    
    }

     可以从继承结构看出就是

    WebApplicationInitializer 
    看一下SpringBootServletInitializer 的onStartUp方法
    @Override
        public void onStartup(ServletContext servletContext) throws ServletException {
            // Logger initialization is deferred in case an ordered
            // LogServletContextInitializer is being used
            this.logger = LogFactory.getLog(getClass());
           //创建容器,打开详细看一下
            WebApplicationContext rootApplicationContext = createRootApplicationContext(servletContext);
            if (rootApplicationContext != null) {
                servletContext.addListener(new SpringBootContextLoaderListener(rootApplicationContext, servletContext));
            }
            else {
                this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not "
                        + "return an application context");
            }
        }
    protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
    //这里创建application应用,同嵌入式容器一样执行public //SpringApplication(ResourceLoader resourceLoader, Class<?>... //primarySources) {
    //        this.resourceLoader = resourceLoader;
    //        Assert.notNull(primarySources, "PrimarySources must //not be null");
    //        this.primarySources = new LinkedHashSet<>//(Arrays.asList(primarySources));
    //        this.webApplicationType = //WebApplicationType.deduceFromClasspath();
    //        setInitializers((Collection) //getSpringFactoriesInstances(ApplicationContextInitializer.class))//;
    //        setListeners((Collection) //getSpringFactoriesInstances(ApplicationListener.class));
    //        this.mainApplicationClass = //deduceMainApplicationClass();
    //    }
            SpringApplicationBuilder builder = createSpringApplicationBuilder();
            builder.main(getClass());
            ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
            if (parent != null) {
                this.logger.info("Root context already created (using as parent).");
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
                builder.initializers(new ParentContextApplicationContextInitializer(parent));
            }
            builder.initializers(new ServletContextApplicationContextInitializer(servletContext));
            builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
            builder = configure(builder);
            builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext)); 
    //得到Spring应用 SpringApplication application
    = builder.build(); if (application.getAllSources().isEmpty() && MergedAnnotations.from(getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) { application.addPrimarySources(Collections.singleton(getClass())); } Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the " + "configure method or add an @Configuration annotation"); // Ensure error pages are registered if (this.registerErrorPageFilter) { application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class)); } application.setRegisterShutdownHook(false);
    //然后执行run方法
    return run(application); }
    /**
         * Called to run a fully configured {@link SpringApplication}.
         * @param application the application to run
         * @return the {@link WebApplicationContext}
         */
        protected WebApplicationContext run(SpringApplication application) {
            return (WebApplicationContext) application.run();
        }
    
    /**
         * Run the Spring application, creating and refreshing a new
         * {@link ApplicationContext}.
         * @param args the application arguments (usually passed from a Java main method)
         * @return a running {@link ApplicationContext}
         */
        public ConfigurableApplicationContext run(String... args) {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            ConfigurableApplicationContext context = null;
            Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
            configureHeadlessProperty();
            SpringApplicationRunListeners listeners = getRunListeners(args);
            listeners.starting();
            try {
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
                configureIgnoreBeanInfo(environment);
                Banner printedBanner = printBanner(environment);
                context = createApplicationContext();
                exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                        new Class[] { ConfigurableApplicationContext.class }, context);
                prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                refreshContext(context);
                afterRefresh(context, applicationArguments);
                stopWatch.stop();
                if (this.logStartupInfo) {
                    new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
                }
                listeners.started(context);
                callRunners(context, applicationArguments);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, listeners);
                throw new IllegalStateException(ex);
            }
    
            try {
                listeners.running(context);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, null);
                throw new IllegalStateException(ex);
            }
            return context;
        }

    执行run以后同嵌入式的一致类,只有一个区别,

    refreshContext(context)时不会再创建嵌入式的servlet容器
    private void createWebServer() {
            WebServer webServer = this.webServer;
            ServletContext servletContext = getServletContext();
            if (webServer == null && servletContext == null) {
                ServletWebServerFactory factory = getWebServerFactory();
                this.webServer = factory.getWebServer(getSelfInitializer());
                getBeanFactory().registerSingleton("webServerGracefulShutdown",
                        new WebServerGracefulShutdownLifecycle(this.webServer));
                getBeanFactory().registerSingleton("webServerStartStop",
                        new WebServerStartStopLifecycle(this, this.webServer));
            }
            else if (servletContext != null) {
                try {
                    getSelfInitializer().onStartup(servletContext);
                }
                catch (ServletException ex) {
                    throw new ApplicationContextException("Cannot initialize servlet context", ex);
                }
            }
            initPropertySources();
        }
  • 相关阅读:
    mysql安装脚本
    vim常用命令
    CentOS 6.5使用国内网易163的源
    053(七十五)
    053(七十四)
    053(七十三)
    053(七十二)
    053(七十一)
    053(七十)
    053(六十九)
  • 原文地址:https://www.cnblogs.com/wxw7blog/p/13341704.html
Copyright © 2020-2023  润新知