springboot内嵌tomcat代码走读(三)

上篇文章走读了springboot中消息处理进入到servlet里了,这次,具体走读了请求消息在servlet里是怎么处理的。这里主要补充servlet和springmvc相关的知识。

servlet相关知识

servlet生命周期

servlet生命周期在servlet的代码里能很清楚的体现出来。代码为:


public interface Servlet {

    //servlet 初始化,这里摘录了部分注释
    /**
     * The servlet container calls the <code>init</code> method exactly once
     * after instantiating the servlet. The <code>init</code> method must
     * complete successfully before the servlet can receive any requests.
    */
    public void init(ServletConfig config) throws ServletException;

    /**
     *
     * Returns a {@link ServletConfig} object, which contains initialization and
     * startup parameters for this servlet. The <code>ServletConfig</code>
     * object returned is the one passed to the <code>init</code> method.
     *
     * <p>
     * Implementations of this interface are responsible for storing the
     * <code>ServletConfig</code> object so that this method can return it. The
     * {@link GenericServlet} class, which implements this interface, already
     * does this.
     *
     * @return the <code>ServletConfig</code> object that initializes this
     *         servlet
     *
     * @see #init
     */
    public ServletConfig getServletConfig();

    /**
     * Called by the servlet container to allow the servlet to respond to a
     * request.
     *
     * <p>
     * This method is only called after the servlet's <code>init()</code> method
     * has completed successfully.
     *
     * <p>
     * The status code of the response always should be set for a servlet that
     * throws or sends an error.
     */
     //真正的处理请求
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

    /**
     * Returns information about the servlet, such as author, version, and
     * copyright.
     *
     * <p>
     * The string that this method returns should be plain text and not markup
     * of any kind (such as HTML, XML, etc.).
     *
     * @return a <code>String</code> containing servlet information
     */
    public String getServletInfo();

    /**
     * Called by the servlet container to indicate to a servlet that the servlet
     * is being taken out of service. This method is only called once all
     * threads within the servlet's <code>service</code> method have exited or
     * after a timeout period has passed. After the servlet container calls this
     * method, it will not call the <code>service</code> method again on this
     * servlet.
     *
     * <p>
     * This method gives the servlet an opportunity to clean up any resources
     * that are being held (for example, memory, file handles, threads) and make
     * sure that any persistent state is synchronized with the servlet's current
     * state in memory.
     */
    public void destroy();
}

从代码中可以看出,servlet生命周期是init-->service-->destory;

具体过程

1、加载与实例化(new)
servlet在启动时或第一次接收到请求时,会到内存中去查询一下是否有servlet实例,有则取出来,没有则new一个出来。
2、初始化(init)
在创建servlet之后,会调用init方法,进行初始化,该步主要是为接收处理请求做一些必要的准备,只会执行一次。
3、提供服务(service)
servlet实例接收客户端的ServletRequest信息,通过request的信息,调用相应的doXXX()方法,并返回response。
4、销毁(destroy)
servlet容器在关闭时,销毁servlet实例。只会执行一次

后面以SpringMVC为例来具体说明servlet的生命周期。

SpringMVC相关知识

这里只简单的罗列一下SpringMVC中M,V,C 的关系。如图:


springMVC框架图.png

1、客户端发送request请求进入到分发器中,DispatcherServlet中。
2、分发器通过uri到控制器映射中去查询相应的处理器(HandlerMapping)。
3、分发器拿到对应的处理器之后,调用处理器响应的接口,返回数据及对应的视图。
4、分发器拿到处理器返回的modelAndView后,查找相应的视同解析器进行渲染。
5、视图将渲染好的结果返回给终端用户进行展示。

下面通过源码的方式看springboot中关于springMVC和servlet相关的实现。

请求消息在SpringMVC中的流向

servlet的创建过程(new)

源码阅读接上篇文章,现在到了servlet的处理了。在这之前,看servlet在springboot中是如何完成实例化及初始化的。
首先看servlet是如何new出来的。springboot中,使用的是dispatcherServlet,DispatcherServlet的类的继承关系图如下

DispatcherServlet.png

该类使用自动装配的方式初始化一个beanName为dispatcherServlet的bean。类名为DispatcherServletAutoConfiguration,具体代码如下:

        @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
            dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
            dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
            dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
            dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
            return dispatcherServlet;
        }

这里就是直接new出来一个servlet,并初始化相关的配置。
这个servlet对象是如何注册到tomcat容器里呢,这里就有下面一个名称为dispatcherServletRegistration的bean来做的事情了,具体代码为:

@Configuration(proxyBeanMethods = false)
    @Conditional(DispatcherServletRegistrationCondition.class)
    @ConditionalOnClass(ServletRegistration.class)
    @EnableConfigurationProperties(WebMvcProperties.class)
    @Import(DispatcherServletConfiguration.class)
    protected static class DispatcherServletRegistrationConfiguration {

        @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
        @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
                WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
            DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
                    webMvcProperties.getServlet().getPath());
            registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            multipartConfig.ifAvailable(registration::setMultipartConfig);
            return registration;
        }

    }

这里需要看一下DispatcherServletRegistrationBean类的继承关系图了。

DispatcherServletRegistrationBean.png

从图中看出,DispatcherServletRegistrationBean实现了接口ServletContextInitializerSpringBoot内嵌tomcat代码走读(一)中,有对这个接口的调用代码。this.webServer = factory.getWebServer(getSelfInitializer());在获取webServer时,传入想改接口的调用。
接下来我们看DispatcherServletRegistrationBean的OnStartup的实现,该方法实现在其父类RegistrationBean中。

    @Override
    public final void onStartup(ServletContext servletContext) throws ServletException {
        String description = getDescription();
        if (!isEnabled()) {
            logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
            return;
        }
        register(description, servletContext);
    }

主要方法register的实现在其子类DynamicRegistrationBean中。

    @Override
    protected final void register(String description, ServletContext servletContext) {
        D registration = addRegistration(description, servletContext);
        if (registration == null) {
            logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
            return;
        }
        configure(registration);
    }

其主要方法addRegistration在其子类ServletRegistrationBean中实现。

    @Override
    protected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {
        String name = getServletName();
        return servletContext.addServlet(name, this.servlet);
    }

servletContextApplicationContextFacadeaddServlet代码为:

    @Override
    public ServletRegistration.Dynamic addServlet(String servletName,
            Servlet servlet) {
        if (SecurityUtil.isPackageProtectionEnabled()) {
            return (ServletRegistration.Dynamic) doPrivileged("addServlet",
                    new Class[]{String.class, Servlet.class},
                    new Object[]{servletName, servlet});
        } else {
            return context.addServlet(servletName, servlet);
        }
    }

Tomcat的ApplicationContext里加入servlet。代码为:

 private ServletRegistration.Dynamic addServlet(String servletName, String servletClass,
            Servlet servlet, Map<String,String> initParams) throws IllegalStateException {

        if (servletName == null || servletName.equals("")) {
            throw new IllegalArgumentException(sm.getString(
                    "applicationContext.invalidServletName", servletName));
        }

        if (!context.getState().equals(LifecycleState.STARTING_PREP)) {
            //TODO Spec breaking enhancement to ignore this restriction
            throw new IllegalStateException(
                    sm.getString("applicationContext.addServlet.ise",
                            getContextPath()));
        }

        Wrapper wrapper = (Wrapper) context.findChild(servletName);

        // Assume a 'complete' ServletRegistration is one that has a class and
        // a name
        if (wrapper == null) {
            wrapper = context.createWrapper();
            wrapper.setName(servletName);
            context.addChild(wrapper);
        } else {
            if (wrapper.getName() != null &&
                    wrapper.getServletClass() != null) {
                if (wrapper.isOverridable()) {
                    wrapper.setOverridable(false);
                } else {
                    return null;
                }
            }
        }

        ServletSecurity annotation = null;
        if (servlet == null) {
            wrapper.setServletClass(servletClass);
            Class<?> clazz = Introspection.loadClass(context, servletClass);
            if (clazz != null) {
                annotation = clazz.getAnnotation(ServletSecurity.class);
            }
        } else {
            wrapper.setServletClass(servlet.getClass().getName());
            wrapper.setServlet(servlet);
            if (context.wasCreatedDynamicServlet(servlet)) {
                annotation = servlet.getClass().getAnnotation(ServletSecurity.class);
            }
        }

        if (initParams != null) {
            for (Map.Entry<String, String> initParam: initParams.entrySet()) {
                wrapper.addInitParameter(initParam.getKey(), initParam.getValue());
            }
        }

        ServletRegistration.Dynamic registration =
                new ApplicationServletRegistration(wrapper, context);
        if (annotation != null) {
            registration.setServletSecurity(new ServletSecurityElement(annotation));
        }
        return registration;
    }

这里主要逻辑是向tomcat里添加servlet。前面我们知道tomcat的体系结构,为了提高扩展性,tomcat里分层定义了很多组件,在最内层组件为Wrapper,这里就是想warapper中添加servlet。这里用默认的wrapper,StandardWrapper,具体代码为:

    @Override
    public void setServlet(Servlet servlet) {
        instance = servlet;
    }

至此,tomcat的基本功能就有了,servlet也有了。但是,当前的servlet还不能用,因为从上面的servlet生命周期看,这只完成了第一步,还有init这一步没有完成。那么,init在什么时候呢。继续看代码。
从代码中可以知道,当第一个请求过来时,servlet才进行init操作。接上篇文章的请求流程图,这里看请求在servlet中的流向。这里流程图从StandardWrapperValue的invoke方法开始进行。
调用流程图如下:


servlet流程图.png

按照流程图,我们走读一下代码,具体看看相关的处理逻辑。
首先看invoke方法里的代码逻辑。

 public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        // Initialize local variables we may need
        boolean unavailable = false;
        Throwable throwable = null;
        // This should be a Request attribute...
        long t1=System.currentTimeMillis();
        requestCount.incrementAndGet();
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
        Context context = (Context) wrapper.getParent();
        
        //去掉一些与主流程关系不太大的代码
        .......

        // Allocate a servlet instance to process this request
        try {
            if (!unavailable) {
                servlet = wrapper.allocate();
            }
        } catch (UnavailableException e) {
          。。。。。。

        MessageBytes requestPathMB = request.getRequestPathMB();
        DispatcherType dispatcherType = DispatcherType.REQUEST;
        if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                requestPathMB);
        // Create the filter chain for this request
        //获取一个ApplicationFilterChain
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        Container container = this.container;
        try {
            if ((servlet != null) && (filterChain != null)) {
               
               。。。。。。

                } else {
                    // 开始处理请求
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                        // 开始处理请求
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }

            }
        } catch (ClientAbortException | CloseNowException e) {
            。。。。。。

        }
    }

上面代码比较长,做了一下删减。主要的功能是初始化servlet(init)和具体调用servlet的service方法。
servletinit方法在allocate()中调用。service方法在doFilter中调用。

servlet初始化过程(init)

具体看下allocate()的实现。

 public Servlet allocate() throws ServletException {

        // If we are currently unloading this servlet, throw an exception
        if (unloading) {
            throw new ServletException(sm.getString("standardWrapper.unloading", getName()));
        }

        boolean newInstance = false;

        // If not SingleThreadedModel, return the same instance every time
        //该处并不知道singleThreadModel的值,使用默认值,在loadServlet中会有确定的赋值,但SingleThreadedModel已经被废弃,这里也走不到该分支中,所以,springboot中的servlet是一个实例。
        //当为SingleThreadedModel类型时,容器中会有多个servlet实例,默认最多20个。
        if (!singleThreadModel) {
            // Load and initialize our instance if necessary
            //前文提到了instance在bean初始化时已经将instance赋值了,这里instance!=null,但instanceInitialized=false
            if (instance == null || !instanceInitialized) {
                synchronized (this) {
                    //该分支在该处不会走到。
                    if (instance == null) {
                       。。。。。。
                    }
                    if (!instanceInitialized) {
                        //init servlet
                        initServlet(instance);
                    }
                }
            }

            if (singleThreadModel) {
                if (newInstance) {
                    // Have to do this outside of the sync above to prevent a
                    // possible deadlock
                    synchronized (instancePool) {
                        instancePool.push(instance);
                        nInstances++;
                    }
                }
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("  Returning non-STM instance");
                }
                // For new instances, count will have been incremented at the
                // time of creation
                if (!newInstance) {
                    countAllocated.incrementAndGet();
                }
                return instance;
            }
        }

        synchronized (instancePool) {
            while (countAllocated.get() >= nInstances) {
                // Allocate a new instance if possible, or else wait
                if (nInstances < maxInstances) {
                    try {
                        instancePool.push(loadServlet());
                        nInstances++;
                    } catch (ServletException e) {
                        throw e;
                    } catch (Throwable e) {
                        ExceptionUtils.handleThrowable(e);
                        throw new ServletException(sm.getString("standardWrapper.allocate"), e);
                    }
                } else {
                    try {
                        instancePool.wait();
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
            }
            if (log.isTraceEnabled()) {
                log.trace("  Returning allocated STM instance");
            }
            countAllocated.incrementAndGet();
            return instancePool.pop();
        }
    }

allocate方法中,instance !=null,singleThreadModel 一直都为false,因为不会走到loadServlet中,singleThreadModel的值一直为false。容器中servlet实例只有一个。提一句:如果singleThreadModel类型为SingleThreadModel时,容器中可以有多个servlet实例,放在一个大小为20的栈中。SingleThreadModel已经被废弃掉了@deprecated As of Java Servlet API 2.4, with no direct replacement.

下面看initServlet()方法的处理逻辑。

    private synchronized void initServlet(Servlet servlet)
            throws ServletException {

        if (instanceInitialized && !singleThreadModel) return;

        // Call the initialization method of this servlet
        try {
            if( Globals.IS_SECURITY_ENABLED) {
                boolean success = false;
                try {
                    Object[] args = new Object[] { facade };
                    SecurityUtil.doAsPrivilege("init",
                                               servlet,
                                               classType,
                                               args);
                    success = true;
                } finally {
                    if (!success) {
                        // destroy() will not be called, thus clear the reference now
                        SecurityUtil.remove(servlet);
                    }
                }
            } else {
                servlet.init(facade);
            }

            instanceInitialized = true;
        } catch (UnavailableException f) {
            unavailable(f);
            throw f;
        } catch (ServletException f) {
            // If the servlet wanted to be unavailable it would have
            // said so, so do not call unavailable(null).
            throw f;
        } catch (Throwable f) {
            ExceptionUtils.handleThrowable(f);
            getServletContext().log(sm.getString("standardWrapper.initException", getName()), f);
            // If the servlet wanted to be unavailable it would have
            // said so, so do not call unavailable(null).
            throw new ServletException
                (sm.getString("standardWrapper.initException", getName()), f);
        }
    }

这段代码很简单,就是调用servlet的init方法。
具体的init方法实现在其父类GenericServlet中。

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

这里的init方法在子类HttpServletBean中。

        // Let subclasses do whatever initialization they like.
        initServletBean();
    }

initServletBean()方法在子类FrameworkServlet中。

@Override
    protected final void initServletBean() throws ServletException {
        
        long startTime = System.currentTimeMillis();

        try {
            this.webApplicationContext = initWebApplicationContext();
            initFrameworkServlet();
        }
        catch (ServletException | RuntimeException ex) {
            logger.error("Context initialization failed", ex);
            throw ex;
        }
    }

initFrameworkServlet()是留给子类实现的一个扩展接口,默认为空实现,主要的逻辑在initWebApplicationContext()中,该方法主要是初始化一些策略,如文件解析器,国际化解析器,主题解析器,处理器映射器,处理器适配器,异常处理器,视图解析器等。具体的实现在子类DispatcherServlet中。
代码如下:

    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    /**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) {
        //文件解析器,没有,返回为空。
        initMultipartResolver(context);
        //国际化解析,没有,返回默认值,AcceptHeaderLocaleResolver
        initLocaleResolver(context);
        //主题解析,没有返回默认值FixedThemeResolver
        initThemeResolver(context);
        //处理器映射,若没有,返回默认值BeanNameUrlHandlerMapping,RequestMappingHandlerMapping,RouterFunctionMapping
        initHandlerMappings(context);
        //处理器适配器,若没有,返回默认值HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter,HandlerFunctionAdapter
        initHandlerAdapters(context);
        //异常解析,若没有,返回默认值ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver
        initHandlerExceptionResolvers(context);
        //异常后,没有返回视图时的默认处理DefaultRequestToViewNameTranslator
        initRequestToViewNameTranslator(context);
        //视图解析,没有返回InternalResourceViewResolver
        initViewResolvers(context);
        //默认值SessionFlashMapManager
        initFlashMapManager(context);
    }

后面通过看具体的请求处理来看上面的处理器如何工作的。

到此,servlet的init方法正式处理完成,就可以提供服务了。

servlet提供服务过程(service)

下面,看service如何处理。
从前文中的代码中可以知道,在调用service之前,需要获取一个ApplicationFilterChain,先来看看ApplicationFilterFactorycreateFilterChain里做了哪些事情。从类名中可以猜到,这里主要是添加一些Filter相关的信息。具体代码为:

public static ApplicationFilterChain createFilterChain(ServletRequest request,
            Wrapper wrapper, Servlet servlet) {

        // Create and initialize a filter chain object
        ApplicationFilterChain filterChain = null;
        if (request instanceof Request) {
            Request req = (Request) request;
            if (Globals.IS_SECURITY_ENABLED) {
                // Security: Do not recycle
                filterChain = new ApplicationFilterChain();
            } else {
                filterChain = (ApplicationFilterChain) req.getFilterChain();
                if (filterChain == null) {
                    filterChain = new ApplicationFilterChain();
                    req.setFilterChain(filterChain);
                }
            }
        } else {
            // Request dispatcher in use
            filterChain = new ApplicationFilterChain();
        }

        filterChain.setServlet(servlet);
        filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

        // Acquire the filter mappings for this Context
        StandardContext context = (StandardContext) wrapper.getParent();
        //获取Filter列表
        FilterMap filterMaps[] = context.findFilterMaps();

        // If there are no filter mappings, we are done
        if ((filterMaps == null) || (filterMaps.length == 0))
            return filterChain;

        // Acquire the information we will need to match filter mappings
        DispatcherType dispatcher =
                (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

        String requestPath = null;
        Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
        if (attribute != null){
            requestPath = attribute.toString();
        }

        String servletName = wrapper.getName();

        // Add the relevant path-mapped filters to this filter chain
        for (FilterMap filterMap : filterMaps) {
            if (!matchDispatcher(filterMap, dispatcher)) {
                continue;
            }
            if (!matchFiltersURL(filterMap, requestPath))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                    context.findFilterConfig(filterMap.getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Add filters that match on servlet name second
        for (FilterMap filterMap : filterMaps) {
            if (!matchDispatcher(filterMap, dispatcher)) {
                continue;
            }
            if (!matchFiltersServlet(filterMap, servletName))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                    context.findFilterConfig(filterMap.getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Return the completed filter chain
        return filterChain;
    }

其中比较重要的一行代码FilterMap filterMaps[] = context.findFilterMaps();,获取过滤器列表。

    @Override
    public FilterMap[] findFilterMaps() {
        return filterMaps.asArray();
    }

这里filterMaps是在什么时候进行赋值的呢?此处又会回到ServletContextInitializer这个接口的onStartup方法里了。
前文里提到过,在createWebServer时,有个方法引用getSelfInitializer。这里同样走到这段代码里。

Filter相关的准备工作

我们在通常在springboot里定义过滤器时,可以使用如下代码:

    @Bean
    public FilterRegistrationBean xxxFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        XxxFilter xxxFilter = new XxxFilter();
        registrationBean.addUrlPatterns("/*");
        registrationBean.setFilter(xxxFilter);
        return registrationBean;

    }

看下FilterRegistrationBean的类图:

FilterRegistrationBean.png

FilterRegistrationBean同样实现了ServletContextInitializer接口。
同时,我们还可以进行如下方式定义过滤器。

@Service
public class TestFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

这种方式没有显式的定义成一个FilterRegistrationBean,在代码中事实上也封装成一个FilterRegistrationBean。接下来看具体的代码实现。
首先看ServletContextInitializeronStartup的调用处代码。

    private void selfInitialize(ServletContext servletContext) throws ServletException {
        prepareWebApplicationContext(servletContext);
        registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            beans.onStartup(servletContext);
        }
    }

getServletContextInitializerBeans()里从bean工厂里获取ServletContextInitializer类型的bean,调用onStartup方法。

    protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
        return new ServletContextInitializerBeans(getBeanFactory());
    }
    public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
            Class<? extends ServletContextInitializer>... initializerTypes) {
        this.initializers = new LinkedMultiValueMap<>();
        this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
                : Collections.singletonList(ServletContextInitializer.class);
        //显式定义为ServletContextInitializer的bean
        addServletContextInitializerBeans(beanFactory);
        //未显式定义为ServletContextInitializer的bean
        addAdaptableBeans(beanFactory);
        List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
                .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
                .collect(Collectors.toList());
        this.sortedList = Collections.unmodifiableList(sortedInitializers);
        logMappings(this.initializers);
    }

显式定义为ServletContextInitializer的bean的处理方法:

    private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
        for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
            for (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,
                    initializerType)) {
                addServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);
            }
        }
    }
private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
            ListableBeanFactory beanFactory) {
        if (initializer instanceof ServletRegistrationBean) {
            Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
            addServletContextInitializerBean(Servlet.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof FilterRegistrationBean) {
            Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
            String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
            addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
        }
        else if (initializer instanceof ServletListenerRegistrationBean) {
            EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
            addServletContextInitializerBean(EventListener.class, beanName, initializer, beanFactory, source);
        }
        else {
            addServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,
                    initializer);
        }
    }
    private void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer,
            ListableBeanFactory beanFactory, Object source) {
        this.initializers.add(type, initializer);
        if (source != null) {
            // Mark the underlying source as seen in case it wraps an existing bean
            this.seen.add(source);
        }
        if (logger.isTraceEnabled()) {
            String resourceDescription = getResourceDescription(beanName, beanFactory);
            int order = getOrder(initializer);
            logger.trace("Added existing " + type.getSimpleName() + " initializer bean '" + beanName + "'; order="
                    + order + ", resource=" + resourceDescription);
        }
    }

未显式定义为ServletContextInitializer的bean

    protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
        MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);
        addAsRegistrationBean(beanFactory, Servlet.class, new ServletRegistrationBeanAdapter(multipartConfig));
        addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());
        for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {
            addAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,
                    new ServletListenerRegistrationBeanAdapter());
        }
    }
    private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,
            Class<B> beanType, RegistrationBeanAdapter<T> adapter) {
        List<Map.Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);
        for (Entry<String, B> entry : entries) {
            String beanName = entry.getKey();
            B bean = entry.getValue();
            if (this.seen.add(bean)) {
                // One that we haven't already seen
                //通过适配器模式,进行处理。
                RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
                int order = getOrder(bean);
                registration.setOrder(order);
                this.initializers.add(type, registration);
                if (logger.isTraceEnabled()) {
                    logger.trace("Created " + type.getSimpleName() + " initializer for bean '" + beanName + "'; order="
                            + order + ", resource=" + getResourceDescription(beanName, beanFactory));
                }
            }
        }
    }
    private static class FilterRegistrationBeanAdapter implements RegistrationBeanAdapter<Filter> {

        @Override
        public RegistrationBean createRegistrationBean(String name, Filter source, int totalNumberOfSourceBeans) {
            FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(source);
            bean.setName(name);
            return bean;
        }

    }

代码比较简单,这里只做代码的罗列,不做详细说明。
接下来看FilterRegistrationBeanonStartup方法的处理逻辑,该方法的实现在其父类RegistrationBean中。

    @Override
    public final void onStartup(ServletContext servletContext) throws ServletException {
        String description = getDescription();
        if (!isEnabled()) {
            logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
            return;
        }
        register(description, servletContext);
    }

register方法在RegistrationBean子类DynamicRegistrationBean中。

    @Override
    protected final void register(String description, ServletContext servletContext) {
        D registration = addRegistration(description, servletContext);
        if (registration == null) {
            logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
            return;
        }
        configure(registration);
    }

addRegistration在其子类AbstractFilterRegistrationBean中实现。

    @Override
    protected Dynamic addRegistration(String description, ServletContext servletContext) {
        Filter filter = getFilter();
        return servletContext.addFilter(getOrDeduceName(filter), filter);
    }

addFilter代码走到ApplicationContextFacade中。

    @Override
    public FilterRegistration.Dynamic addFilter(String filterName,
            Filter filter) {
        if (SecurityUtil.isPackageProtectionEnabled()) {
            return (FilterRegistration.Dynamic) doPrivileged("addFilter",
                    new Class[]{String.class, Filter.class},
                    new Object[]{filterName, filter});
        } else {
            return context.addFilter(filterName, filter);
        }
    }

最后走到ApplicationContext中。

 private FilterRegistration.Dynamic addFilter(String filterName,
            String filterClass, Filter filter) throws IllegalStateException {


        FilterDef filterDef = context.findFilterDef(filterName);

        if (filterDef == null) {
            filterDef = new FilterDef();
            filterDef.setFilterName(filterName);
            context.addFilterDef(filterDef);
        } else {
            if (filterDef.getFilterName() != null &&
                    filterDef.getFilterClass() != null) {
                return null;
            }
        }

     ......

        return new ApplicationFilterRegistration(filterDef, context);
    }

最后将FilterDef加入到StandradContextfilterDefs中。
回过头来,看DynamicRegistrationBean中register的第二个主要调用的方法configure()
对于过滤器来说,实现方法在AbstractFilterRegistrationBean中。

@Override
    protected void configure(FilterRegistration.Dynamic registration) {
        super.configure(registration);
        EnumSet<DispatcherType> dispatcherTypes = this.dispatcherTypes;
        if (dispatcherTypes == null) {
            T filter = getFilter();
            if (ClassUtils.isPresent("org.springframework.web.filter.OncePerRequestFilter",
                    filter.getClass().getClassLoader()) && filter instanceof OncePerRequestFilter) {
                dispatcherTypes = EnumSet.allOf(DispatcherType.class);
            }
            else {
                dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
            }
        }
        Set<String> servletNames = new LinkedHashSet<>();
        for (ServletRegistrationBean<?> servletRegistrationBean : this.servletRegistrationBeans) {
            servletNames.add(servletRegistrationBean.getServletName());
        }
        servletNames.addAll(this.servletNames);
        if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
            registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, DEFAULT_URL_MAPPINGS);
        }
        else {
            if (!servletNames.isEmpty()) {
                registration.addMappingForServletNames(dispatcherTypes, this.matchAfter,
                        StringUtils.toStringArray(servletNames));
            }
            if (!this.urlPatterns.isEmpty()) {
                registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,
                        StringUtils.toStringArray(this.urlPatterns));
            }
        }
    }

registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, DEFAULT_URL_MAPPINGS);这里的方法将每个filter通过StandardContext的addFilterMapBefore方式,塞到filterMap中的arrays中。通过findFilterMaps就能得到所有的filter了。
到此,Filter相关的准备工作完成。

需要补充上面流程的流程图

回到service

回到前文的ApplicationFilterChain的获取上。ApplicationFilterFactory里通过context.findFilterMaps();获取所有的过滤器,放入filterChain中。
StandardWrapperValue中代码继续往下走,调用了ApplicationFilterChain的doFilter方法。

 private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {

        // 遍历所有的filter,这里就是为啥我们在定义Filter时,为了让chain能顺利的走完需要调用chain.doFilter()的原因。
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();

                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                }
               。。。。。。
                } else {
                    filter.doFilter(request, response, this);
                }
            } 
            。。。。。。
            }
            return;
        }

        // We fell off the end of the chain -- call the servlet instance
        try {
            。。。。。。
            if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse) &&
                    Globals.IS_SECURITY_ENABLED ) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal =
                    ((HttpServletRequest) req).getUserPrincipal();
                Object[] args = new Object[]{req, res};
                SecurityUtil.doAsPrivilege("service",
                                           servlet,
                                           classTypeUsedInService,
                                           args,
                                           principal);
            } else {
                servlet.service(request, response);
            }
        } 。。。。。。
        。。。。。。
        }
    }

以上代码就进入到了servlet的另外一个生命周期了,提供service服务了。
下篇文章,我们具体看下service接口里的逻辑。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345