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.prepareWebApplicationContext(servletContext);
        // 注册Web的Application作用域
        this.registerApplicationScope(servletContext);
        // 将Servlet相关的参数注册为Bean,例如servletContext,servletConfig,contextParameters,contextAttributes这些Bean
        WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
        // 获取到容器中所有ServletContextInitializer类型的Bean,并执行初始化操作
        Collection<ServletContextInitializer> servletContextInitializerBean = new ServletContextInitializerBeans(getBeanFactory());
        // 执行提取到的ServletContextInitializer,包括动态添加Servlet三大组件的RegistrationBean
        for (ServletContextInitializer beans : servletContextInitializerBean) {
            // 执行这个初始化的onStartup方法
            beans.onStartup(servletContext);
        }
    }

    // 注册ServletContext:Application作用域
    private void registerApplicationScope(ServletContext servletContext) {
        ServletContextScope appScope = new ServletContextScope(servletContext);
        // 注册到BeanFactory中
        getBeanFactory().registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
        // 保存到servletContext中
        servletContext.setAttribute(ServletContextScope.class.getName(), appScope);
    }

    // 提前处理下Web的上下文对象,给上下文设置ServletContext
    protected void prepareWebApplicationContext(ServletContext servletContext) {
        // WebApplicationContext.class.getName() + ".ROOT",获取Spring父容器
        Object rootContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        // 如果已经创建的父容器
        if (rootContext != null) {
            // 校验当前容器不能是自己,因为自身已经初始化过了
            if (rootContext == this) {
                throw new IllegalStateException("Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ServletContextInitializers!");
            }
            return;
        }
        Log logger = LogFactory.getLog(ContextLoader.class);
        try {
            // 将当前上下文对象保存到ServletContext中
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this);
            // 该当前上下文设置ServletContext
            this.setServletContext(servletContext);
        } catch (RuntimeException | Error ex) {
            // 如果发生异常,将异常保存到该ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE对应的Key中
            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
            throw ex;
        }
    }

    // 从Spring中获取ServletWebServerFactory的Bean
    protected ServletWebServerFactory getWebServerFactory() {
        // 从Spring中获取ServletWebServerFactory的Bean
        String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
        // 如果不存在,抛出异常
        if (beanNames.length == 0) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " + "ServletWebServerFactory bean.");
        }
        // 如果存在多个,抛出异常
        if (beanNames.length > 1) {
            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
        }
        // 获取容器中的Bean
        return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
    }

    public void setServletContext(@Nullable ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    // 动态注册Servlet
    // 动态注入Filter和Listener都是差不多
    class DispatcherServletRegistrationBean
            // extends ServletRegistrationBean<DispatcherServlet>
            // extends DynamicRegistrationBean<ServletRegistration.Dynamic>
            extends RegistrationBean implements ServletContextInitializer {

        // 该初始化器的初始化方法,这里是动态添加Servlet三大组件的入口
        @Override
        public final void onStartup(ServletContext servletContext) throws ServletException {
            // 动态注册Servlet
            this.register(description, servletContext);
        }

        @Override
        protected final void register(String description, ServletContext servletContext) {
            // 动态添加Servlet,返回javax.servlet提供的ServletRegistration.Dynamic类
            D registration = this.addRegistration(description, servletContext);
            // 对该动态注册的对象进行配置
            this.configure(registration);
        }

        // 动态注册,该方法是父类中抽象的方法,对应不同的实现
        // 在Filter中,这里是addFilter,在Servlet中,就是addServlet
        @Override
        protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
            // 动态添加Servlet,调用java.servlet的API
            String name = getServletName();
            return servletContext.addServlet(name, this.servlet);
        }

        // 对该动态注册的对象进行配置,该方法是父类中抽象的方法,对应不同的实现
        // 在Filter中,这里是配置filter的拦截路径,在Servlet中,就是配置拦截URL,设置初始化参数,设置文件配置信息等等
        @Override
        protected void configure(ServletRegistration.Dynamic registration) {
            super.configure(registration) {
                // 这个Servlet组件是否支持异步
                registration.setAsyncSupported(this.asyncSupported);
                // 如果提供了初始化参数
                if (!this.initParameters.isEmpty()) {
                    // 设置初始化参数
                    registration.setInitParameters(this.initParameters);
                }
            }
            // 设置Servlet拦截的路径
            String[] urlMapping = StringUtils.toStringArray(this.urlMappings);
            if (urlMapping.length == 0 && this.alwaysMapUrl) {
                urlMapping = DEFAULT_MAPPINGS;
            }
            if (!ObjectUtils.isEmpty(urlMapping)) {
                registration.addMapping(urlMapping);
            }
            // 设置启动的时机
            registration.setLoadOnStartup(this.loadOnStartup);
            // 如果设置了文件相关配置
            if (this.multipartConfig != null) {
                // 设置文件配置信息
                registration.setMultipartConfig(this.multipartConfig);
            }
        }

    }

    // 封装了Spring容器中所有ServletContextInitializer类型的Bean
    class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {
        // dispatcher_servlet的名称 dispatcherServlet
        private static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";
        /**
         * 不同ServletContextInitializer类型提供的Bean对象
         *
         * @see {@link ServletWebServerApplicationContext.ServletContextInitializerBeans#addServletContextInitializerBean(String, ServletContextInitializer, ListableBeanFactory)}
         */
        private final Set<Object> seen = new HashSet<>();
        // 需要初始化的ServletContextInitializer集合
        // 当ServletContextInitializer类型为RegistrationBean,key为Servlet三大组件的类型
        // 当ServletContextInitializer就是一个普通的ServletContextInitializer,key为本身
        private final MultiValueMap<Class<?>, ServletContextInitializer> initializers;
        // 需要查找的ServletContextInitializer的类型
        private final List<Class<? extends ServletContextInitializer>> initializerTypes;
        // 对this.initializers的values进行排序后的ServletContextInitializer
        private List<ServletContextInitializer> sortedList;

        /**
         * @param beanFactory      bean工厂
         * @param initializerTypes 指定类型的初始化器
         */
        public ServletContextInitializerBeans(ListableBeanFactory beanFactory, Class<? extends ServletContextInitializer>... initializerTypes) {
            this.initializers = new LinkedMultiValueMap<>();
            // 如果没有指定,默认为ServletContextInitializer类型
            this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes) : Collections.singletonList(ServletContextInitializer.class);
            // 处理所有的ServletContextInitializer的Bean,并将这个ServletContextInitializer提供的Bean对象保存
            this.addServletContextInitializerBeans(beanFactory);
            // 将Spring中的Servlet三大组件,适配为RegistrationBean类型,然后通过RegistrationBean对它们进行动态祖册
            this.addAdaptableBeans(beanFactory);
            // 将ServletContextInitializer进行排序
            List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
                    // 将所有的ServletContextInitializer进行合并并排序
                    .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
                    .collect(Collectors.toList());
            // 保存排好序的ServletContextInitializer
            this.sortedList = Collections.unmodifiableList(sortedInitializers);
            // 打印映射日志
            this.logMappings(this.initializers);
        }

        // 打印映射日志
        public void logMappings(MultiValueMap<Class<?>, ServletContextInitializer> initializers) {
            if (logger.isDebugEnabled()) {
                this.logMappings("filters", initializers, Filter.class, FilterRegistrationBean.class);
                this.logMappings("servlets", initializers, Servlet.class, ServletRegistrationBean.class);
            }
        }

        /**
         * @param name             组件的名称概要
         * @param initializers     所有的ServletContextInitializer
         * @param type             三大组件的类型
         * @param registrationType 三个组件对应的RegistrationBean类型
         */
        private void logMappings(String name, MultiValueMap<Class<?>, ServletContextInitializer> initializers, Class<?> type, Class<? extends RegistrationBean> registrationType) {

            List<ServletContextInitializer> registrations = new ArrayList<>();
            // 获取指定RegistrationBean类型对应的Initializer
            registrations.addAll(initializers.getOrDefault(registrationType, Collections.emptyList()));
            // 获取指定三大组件类型对应的initializer
            registrations.addAll(initializers.getOrDefault(type, Collections.emptyList()));
            // 使用,拼接打印
            String info = registrations.stream().map(Object::toString).collect(Collectors.joining(", "));
            logger.debug("Mapping " + name + ": " + info);
        }

        /**
         * 将Spring中的Servlet三大组件,适配为RegistrationBean类型,然后通过RegistrationBean对它们进行动态祖册
         */
        protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
            // 获取Multipart相关配置
            MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory) {
                // 获取MultipartConfigElement类型的Bean返回,只返回一个
                List<Entry<String, MultipartConfigElement>> beans = this.getOrderedBeansOfType(beanFactory, MultipartConfigElement.class);
                return beans.isEmpty() ? null : beans.get(0).getValue();
            }
            // 将Spring中的Servlet三大组件中的Servlet组件,通过RegistrationBean类动态注册,该Serverlet对应的RegistrationBean是通过ServletRegistrationBeanAdapter来生成
            this.addAsRegistrationBean(beanFactory, Servlet.class, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
            // 将Spring中的Servlet三大组件中的Filter组件,通过RegistrationBean类动态注册,该Filter对应的RegistrationBean是通过FilterRegistrationBeanAdapter来生成
            this.addAsRegistrationBean(beanFactory, Filter.class, Filter.class, new FilterRegistrationBeanAdapter());
            // types.add(ServletContextAttributeListener.class);
            // types.add(ServletRequestListener.class);
            // types.add(ServletRequestAttributeListener.class);
            // types.add(HttpSessionAttributeListener.class);
            // types.add(HttpSessionListener.class);
            // types.add(ServletContextListener.class);
            Set<Class<?>> types = ServletListenerRegistrationBean.getSupportedTypes();
            for (Class<?> listenerType : types) {
                // 将Spring中的Servlet三大组件中的Listener组件,通过RegistrationBean类动态注册,该Listener对应的RegistrationBean是通过ServletListenerRegistrationBeanAdapter来生成
                this.addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType, new ServletListenerRegistrationBeanAdapter());
            }
        }

        /**
         * 将Spring中的Servlet三大组件,通过RegistrationBean类,动态注册三大组件
         * RegistrationBean本身是一个ServletContextInitializer,该类型用于注册Servlet,Filter,Listener...Servlet类型组件的抽象
         * 该类可以提供一个对象类型的实例,例如FilterRegistrationBean提供Filter,ServletRegistrationBean注册Servlet
         * 为什么要创建RegistrationBean?因为潜规定只有RegistrationBean才有注册组件的权利,所以我们注册的三大组件的Bean对象,例如Servlet,Filter对象
         * 我们就需要包装成RegistrationBean,通过RegistrationBean来动态注册这些组件,为什么说是潜规定呢?
         * 因为我们拿到了ServletContext对象之后,我们自己也可以通过addXXX来注册组件
         *
         * @param beanFactory Bean工厂
         * @param type        Servlet三大组件的抽象类型  Servlet.class,Filter.class,EventListener.class
         * @param beanType    Servlet.class,Filter.class,EventListener.class: Servlet三大组件的Bean类型,其中Listener类型有多种,可以是session,Request的,还有其他类型的
         * @param adapter     创建RegistrationBean的适配器,而RegistrationBean就是动态注册Servlet三大组件的抽象类
         */
        private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
            // 获取Servlet三大组件的抽象类型的Bean,并且在this.seen中保存的bean需要被排除
            List<Map.Entry<String, B>> entries = this.getOrderedBeansOfType(beanFactory, beanType, this.seen);
            // 遍历所有该类型的Bean
            for (Entry<String, B> entry : entries) {
                String beanName = entry.getKey();
                B bean = entry.getValue();
                // 如果这个组件能保存成功,表示在之前没有被动态添加过
                // seen保存之前处理过的Servelt三个组件
                if (this.seen.add(bean)) {
                    // 创建一个RegistrationBean,RegistrationBean本身是一个ServletContextInitializer,该类型用于注册Servlet,Filter,Listener...Servlet类型组件的抽象
                    // 该类可以提供一个对象类型的实例,例如FilterRegistrationBean提供Filter,ServletRegistrationBean注册Servlet
                    // 为什么要创建RegistrationBean?因为潜规定只有RegistrationBean才有注册组件的权利,所以我们注册的三大组件的Bean对象,例如Servlet,Filter对象
                    // 我们就需要包装成RegistrationBean,通过RegistrationBean来动态注册这些组件,为什么说是潜规定呢?
                    // 因为我们拿到了ServletContext对象之后,我们自己也可以通过addXXX来注册组件
                    // 使用RegistrationBean的适配器创建一个RegistrationBean实例
                    RegistrationBean registrationBean = adapter.createRegistrationBean(beanName, bean, entries.size());
                    // 获取该Bean的顺序,因为Servelt三大组件的顺序还是比较重要
                    int order = getOrder(bean);
                    // 设置优先级
                    registration.setOrder(order);
                    // 保存该RegistrationBean到Map中,类型为对应的组件类型,它是一个ServletContextInitializer,保存到容器中
                    this.initializers.add(type, registration);
                }
            }
        }


        /**
         * 根据类型获取排序之后的Bean对象
         *
         * @param beanFactory bean工厂
         * @param type        bean类型
         * @param excludes    需要排序的类型或者beanName
         * @return 符合条件的这些Bean
         */
        private <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type, Set<?> excludes) {
            // 获取指定类型的所有Bean名称
            String[] names = beanFactory.getBeanNamesForType(type, true, false);
            Map<String, T> map = new LinkedHashMap<>();
            // 遍历所有的beanName
            for (String name : names) {
                // 如果该beaName没有被排除,并且该类不是作用域的代理类
                if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
                    // 获取该Bean对象
                    T bean = beanFactory.getBean(name, type);
                    // 如果该Bean没有被排除
                    if (!excludes.contains(bean)) {
                        // 保存该Bean
                        map.put(name, bean);
                    }
                }
            }
            List<Entry<String, T>> beans = new ArrayList<>(map.entrySet());
            // 对这些类型的Bean进行排序
            beans.sort((o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue()));
            // 返回保存的所有bean
            return beans;
        }

        // 处理所有的ServletContextInitializer的Bean
        public void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
            // 遍历指定的ServletContextInitializer类型
            for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
                // 根据指定类型获取ServletContextInitializer的Bean
                for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory, initializerType)) {
                    // 根据不同的类型进行区分做不同的处理,并保存该initializer
                    this.addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
                }
            }
        }

        // 根据不同的类型进行区分做不同的处理,并保存该initializer,同时将初始化器提供的Servlet相关组件的Bean进行保存
        public void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
            // 如果初始化器是ServletRegistrationBean类型,表示该Bean是一个用于动态注册Servlet的Bean对象
            if (initializer instanceof ServletRegistrationBean) {
                // 提供的这个servlet可以是bean,也可以不是bean,如果需要给spring管理,那就需要注册为bean
                // 如果我们自己写的,就看自己需不需要注册为bean,spring内置的这些都注册为bean了
                // 下面的Listener和Filter也是一样的
                Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
                this.addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
                return;
            }
            // 如果初始化器是FilterRegistrationBean类型,表示该Bean是一个用于动态注册Filter的Bean对象
            if (initializer instanceof FilterRegistrationBean) {
                // 保存该initializer,并指定该类处理的源类型为Servlet
                Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
                this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
                return;
            }
            // 如果初始化器是DelegatingFilterProxyRegistrationBean类型,表示该Bean是一个用于动态注册Filter的Bean对象
            // 这个对象与FilterRegistrationBean区别
            // DelegatingFilterProxyRegistrationBean: 通过getFilter返回的是一个代理对象DelegatingFilterProxy(静态代理)
            // 这个代理对象DelegatingFilterProxy执行实际上是依靠该对象引用的beanName对应的容器中的Filter进行工作的
            // 而FilterRegistrationBean
            if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
                String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
                this.addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
                return;
            }
            // 如果初始化器是ServletListenerRegistrationBean类型,表示该Bean是一个用于动态注册Servlet的listener的Bean对象
            if (initializer instanceof ServletListenerRegistrationBean) {
                EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
                this.addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
                return;
            }
            // 其他情况,保存该initializer,并将当前initializer对象本身进行保存
            this.addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory, initializer);
        }


        /**
         * 保存该initializer,同时记录该initializer提供的bean对象,可能是ServletContextInitializer本身,也可能是Servlet,Filter,Listener
         *
         * @see {@link ServletContextInitializerBeans#addServletContextInitializerBean(String, ServletContextInitializer, ListableBeanFactory)}
         */
        public void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer, ListableBeanFactory beanFactory, Object source) {
            // 保存找到的ServletContextInitializer
            this.initializers.add(type, initializer);
            // 保存该ServletContextInitializer类需要的源类型
            if (source != null) {
                this.seen.add(source);
            }
        }

    }

    // 注册Bean的工具类
    class WebApplicationContextUtils {
        // 注册Servelt相关的Bean,不注册ServletConfig
        public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, @Nullable ServletContext sc) {
            this.registerEnvironmentBeans(bf, sc, null);
        }

        // 注册Servelt相关的所有Bean
        public static void registerEnvironmentBeans(ConfigurableListableBeanFactory bf, ServletContext servletContext, @Nullable ServletConfig servletConfig) {
            // 如果容器中不存在servletContext的Bean
            if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) {
                // 注册该Bean
                bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
            }
            // 如果不存在servletConfig的Bena
            if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {
                // 注册该Bean
                bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig);
            }
            // 如果容器中不存在contextParameters的Bean
            if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) {
                Map<String, String> parameterMap = new HashMap<>();
                // 加载servletContext中的初始化配置
                if (servletContext != null) {
                    // ServletContext 对象代表了整个 web 应用程序的上下文,在整个应用程序范围内共享
                    Enumeration<?> paramNameEnum = servletContext.getInitParameterNames();
                    // 将数据保存到parameterMap中
                    while (paramNameEnum.hasMoreElements()) {
                        String paramName = (String) paramNameEnum.nextElement();
                        parameterMap.put(paramName, servletContext.getInitParameter(paramName));
                    }
                }
                // 加载servletConfig中的初始化配置
                if (servletConfig != null) {
                    // ServletConfig对象代表了一个特定的Servlet的配置信息,I每个Servlet都有自己的ServletConfig对象
                    Enumeration<?> paramNameEnum = servletConfig.getnitParameterNames();
                    while (paramNameEnum.hasMoreElements()) {
                        String paramName = (String) paramNameEnum.nextElement();
                        parameterMap.put(paramName, servletConfig.getInitParameter(paramName));
                    }
                }
                // 注册该contextParameters的Bean
                bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME, Collections.unmodifiableMap(parameterMap));
            }
            // 如果容器中不存在contextAttributes的Bean
            if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) {
                Map<String, Object> attributeMap = new HashMap<>();
                if (servletContext != null) {
                    // 获取上下文中所有的属性配置
                    Enumeration<?> attrNameEnum = servletContext.getAttributeNames();
                    while (attrNameEnum.hasMoreElements()) {
                        String attrName = (String) attrNameEnum.nextElement();
                        attributeMap.put(attrName, servletContext.getAttribute(attrName));
                    }
                }
                // 将ServletContext中所有的属性注册为Bean
                bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap));
            }

        }

        // 注册Servelt相关的Bean,不注册ServletConfig
        public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
            // 注册Request域
            beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
            // 注册Session域
            beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
            if (sc != null) {
                // 注册application域
                ServletContextScope appScope = new ServletContextScope(sc);
                beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
                sc.setAttribute(ServletContextScope.class.getName(), appScope);
            }
            // 注册对这些类型的ObjectFactory依赖,例如: 注入ServletRequest,使用返回RequestObjectFactory
            beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
            beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
            beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
            beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
        }
    }

}

// 上下文环境对象
public class ConfigurableEnvironment {

    public AbstractEnvironment() {
        // 自定义配置属性源
        this.customizePropertySources(this.propertySources);
    }

    // 自定义配置属性源,该方法是AbstractEnvironment的空实现的钩子方法,这里提供两个不同实现源码
    protected void customizePropertySources(MutablePropertySources propertySources) {
        // org.springframework.core.env.StandardEnvironment.customizePropertySources
        {
            // systemProperties
            propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
            // systemEnvironment
            propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
        }
        // org.springframework.web.context.support.StandardServletEnvironment.customizePropertySources
        {
            // servletConfigInitParams,这个目前只是一个占位
            propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
            // servletContextInitParams,这个目前只是一个占位
            propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
            if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
                propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
            }
            // 调用父类的自定义方法
            super.customizePropertySources(propertySources);
        }
    }

    // 保存了程序中所有的配置属性键值对集合
    public final MutablePropertySources propertySources = new MutablePropertySources();

    // 获取程序中所有的配置属性键值对集合
    public MutablePropertySources getPropertySources() {
        return this.propertySources;
    }

    public class MutablePropertySources {
        // 保存了程序中所有的配置属性键值对集合,每一个单独的配置都是一个PropertySource,其中PropertySource具有name和源数据
        public final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();
    }
}
@Configuration
public class FB {
    static class LuckFilter implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.err.println(request.getRemoteHost());
            chain.doFilter(request, response);
        }
    }

    // 这种方式,最终也会将Filter包装成FilterRegistrationBean注册ServletContext中
    @Component
    static class LuckFilter1 implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.err.println(request.getRemoteHost());
            chain.doFilter(request, response);
        }
    }

    @Bean("luckFilterRegistrationBean")
    public FilterRegistrationBean<LuckFilter> filterRegistrationBean() {
        FilterRegistrationBean<LuckFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new LuckFilter());
        return registrationBean;
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Spring Boot使用Servlet有两种方式:一种是通过注解方式,一种是通过WebMvcConfigurerAdapter方式。 1. 通过注解方式 通过使用@WebServlet、@WebFilter、@WebListener注解,可以在Spring Boot项目使用Servlet。 示例代码: ```java @WebServlet(name = "myServlet", urlPatterns = "/myServlet") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello World!"); } } ``` 在启动类上添加@ServletComponentScan注解: ```java @SpringBootApplication @ServletComponentScan public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 2. 通过WebMvcConfigurerAdapter方式 通过继承WebMvcConfigurerAdapter,实现addServlet方法,可以在Spring Boot项目使用Servlet。 示例代码: ```java @Configuration public class MyWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter { @Override public void addServlet(ServletRegistrationBean registrationBean) { registrationBean.setServlet(new MyServlet()); registrationBean.addUrlMappings("/myServlet"); registrationBean.setLoadOnStartup(1); } } ``` 需要注意的是,在Spring Boot 2.0及以上版本,WebMvcConfigurerAdapter已经被废弃,推荐使用WebMvcConfigurer接口,示例代码如下: ```java @Configuration public class MyWebMvcConfigurer implements WebMvcConfigurer { @Bean public ServletRegistrationBean<MyServlet> myServletRegistrationBean() { ServletRegistrationBean<MyServlet> registrationBean = new ServletRegistrationBean<>(); registrationBean.setServlet(new MyServlet()); registrationBean.addUrlMappings("/myServlet"); registrationBean.setLoadOnStartup(1); return registrationBean; } } ``` 以上两种方式均可以在Spring Boot项目使用Servlet,具体选择哪种方式,可以根据实际业务需求来决定。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值