SpringBoot中,如何动态的注入Servlet的三大组件Servlet,Filter,Listener

// Servlet上下文对象
public class ServletWebServerApplicationContext {

    // 后置处理BeanFactory
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 添加处理ServletContextAware,ServletConfigAware回调的Bean的后置处理器
        beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
        // 忽略依赖的接口的注入
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        // 注册web作用域
        this.registerWebApplicationScopes();
    }

    // 注册Web作用域
    private void registerWebApplicationScopes() {
        // 保存之前的作用域
        ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());
        // 注册Request,Session,Application域
        WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
        // 合并之前的和最新保存的作用域
        existingScopes.restore();
    }

    // 容器即将刷新
    protected void onRefresh() {
        super.onRefresh();
        // 创建web服务器
        this.createWebServer();
    }

    // 创建web服务器
    private void createWebServer() {
        // 获取Web服务器对象
        WebServer webServer = this.webServer;
        // 获取ServletContext对象
        ServletContext servletContext = this.servletContext;
        // 如果都为空,表示没有初始化Web容器
        if (webServer == null && servletContext == null) {
            // 获取创建WebServer的工厂
            ServletWebServerFactory factory = this.getWebServerFactory();
            // 获取容器中所有的ServletContextInitializer初始化器
            ServletContextInitializer initializer = this.getSelfInitializer();
            // 创建Web服务器
            this.webServer = factory.getWebServer(initializer) {
                // Tomcat的实现
                // 创建Tomcat服务器
                Tomcat tomcat = new Tomcat();
                // 设置一些相关属性
                File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
                tomcat.setBaseDir(baseDir.getAbsolutePath());
                Connector connector = new Connector(this.protocol);
                connector.setThrowOnFailure(true);
                tomcat.getService().addConnector(connector);
                customizeConnector(connector) {
                    int port = Math.max(getPort(), 0);
                    connector.setPort(port);
                    // 对连接进行自定义
                    for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
                        customizer.customize(connector);
                    }
                }
                tomcat.setConnector(connector);
                tomcat.getHost().setAutoDeploy(false);
                // 返回WebServer对象
                return getTomcatWebServer(tomcat) {
                    // 启动Tomcat服务器
                    this.tomcat.start();
                }
            }
        }
        // 如果servletContext初始化了
        else if (servletContext != null) {
            // 获取容器中所有的ServletContextInitializer初始化器
            ServletContextInitializer initializer = this.getSelfInitializer();
            // 回调该ServletContextInitializer接口的onStartup
            /**
             * @see {@link ServletWebServerApplicationContext#getSelfInitializer}执行
             * 其实就是触发{@link ServletWebServerApplicationContext#selfInitialize}执行
             */
            initializer.onStartup(servletContext);
        }
        // 初始化Servlet相关的属性配置
        this.initPropertySources();
    }

    // 初始化Servlet相关的属性配置
    protected void initPropertySources() {
        ConfigurableEnvironment env = getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null) {
                WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig)
                {
                    // 环境对象中,是否包含servletContextInitParams的配置
                    // 在创建环境对象的时候,就已经在构造方法中进行了配置,配置的属性源是一个占位的,类型为StubPropertySource
                    String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;
                    // 将占位的属性源替换为ServletContextPropertySource这种属性源
                    if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
                        // 这样从servletContextInitParams获取的配置,实际上就是从servletContext获取配置
                        sources.replace(name, new ServletContextPropertySource(name, servletContext));
                    }
                    // 环境对象中,是否包含servletConfigInitParams的配置
                    // 在创建环境对象的时候,就已经在构造方法中进行了配置,配置的属性源是一个占位的,类型为StubPropertySource
                    name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;
                    // 将占位的属性源替换为ServletConfigPropertySource这种属性源
                    if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
                        // 这样从servletConfigInitParams获取的配置,实际上就是从servletConfig获取配置
                        sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
                    }
                }
            }
        }
    }

    // 获取容器中所有的ServletContextInitializer初始化器
    private ServletContextInitializer getSelfInitializer() {
        // return this::selfInitialize;
        return new ServletContextInitializer() {
            /**
             * 该对象是由Tomcat创建的,onStartup最终也是通过tomcat回调的
             * @see {@link org.springframework.boot.web.embedded.tomcat.TomcatStarter}
             *       该类实现了ServletContainerInitializer接口,该接口为servlet规范中的初始化接口
             *       通过SCI,META-INF/services/javax.servlet.ServletContainerInitializer方法注册
             *       但是,TomcatStarter是通过手动创建的,并没有使用SCI注册
             *       在{@link org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#configureContext}中创建的对象
             *       其中,在此刻与Spring提供的ServletContextInitializer接口上下文初始化器进行整合,将initializers传递给了TomcatStarter
             *       然后调用Api,context.addServletContainerInitializer(starter, NO_CLASSES),将TomcatStarter动态注册到Tomcat上下文中
             *       最终Tomcat就会执行所有实现了ServletContainerInitializer接口的onStartup方法
             *       而在TomcatStarter内部的onStartup方法中,执行所有ServletContextInitializer的onStartup方法
             *
             *       tip: TomcatStarter注册的方式是使用APi调用,而不是使用SCI,SCI的方式为: 在META-INF/services/javax.servlet.ServletContainerInitializer文件中添加实现类的全类名
             * @param servletContext Servlet上下文,Tomcat创建好了ServletContext对象才会回调该方法
             */
            @Override
            public void onStartup(ServletContext servletContext) throws ServletException {
                ServletWebServerApplicationContext.this.selfInitialize(servletContext);
            }
        }
    }

    // 获取容器中所有的ServletContextInitializer初始化器
    // 并且回调初始化方法
    private void selfInitialize(ServletContext servletContext) {
        // 提前处理下Web的上下文对象,给上下文设置ServletContext
        this.prepareW
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值