springboot中使用过滤器、拦截器、监听器、Servlet

  监听器:listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:1、统计在线人数和在线用户2、系统启动时加载初始化信息3、统计网站访问量4、记录用户访问路径。

  过滤器:Filter是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

  拦截器:Interceptor 在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。

 

  过滤器Filter只在Servlet前后起作用,而拦截器Interceptor可以深入到方法前后,异常抛出前后等,具有更大的弹性。所以在Spring的程序里应该尽量用拦截器,在简单的java—web项目里可以使用较为简单的过滤器。

对于一个SpringMVC项目,其执行过程如下:

Filter chain 放行前

DispatcherServlet doDispatch 方法

  inteceptors - preHandle

  invoke 方法

  inteceptors - postHandle

  inteceptors - afterCompletion

Filter chain 放行后代码

 

javax.servlet.ServletContext提供了动态注册的接口:

public ServletRegistration.Dynamic addServlet(String servletName, String className);

public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet);

public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass);

对于filter和listener 也有对应的add方法。比如addFilter、addListener。 比如动态注册一个Servlet, 如下:

        // Register Servlet 
        ServletRegistration sr = servletContext.addServlet("DynamicServlet", new MyServlet()); 
        sr.setInitParameter("servletInitName", "servletInitValue"); 
        sr.addMapping("/*");

 

  其实Spring 提供的一套注册的方式原理也是基于ServletContext 的动态注册。只不过Spring 进行了封装,暴露出一些简单操作的接口 。

 

==========1.过滤器的使用===========

  过滤器的使用有两种方式。

1.基于注册的方式

  这种使用方式简单:编写过滤器、注入到spring中。

过滤器1:

package cn.qlq.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

public class MyFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("=========enter filter===========");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

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

    }

}

过滤器2:

package cn.qlq.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
public class MyFilter2 implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("=========enter filter (MyFilter2)===========");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

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

    }

}

 

注册到spring中:(这种注册方式的顺序可以过滤器的指定)

package cn.qlq.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import cn.qlq.filter.MyFilter;
import cn.qlq.filter.MyFilter2;

/**
 * 注册filter,setOrder可以控制顺序
 * 
 * @author Administrator
 *
 */
 @Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean registMyFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        registration.addUrlPatterns("/*");
        registration.setName("myFilter");
        registration.setOrder(2);
        return registration;
    }

    @Bean
    public FilterRegistrationBean registMyFilter2() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter2());
        registration.addUrlPatterns("/*");
        registration.setName("myFilter2");
        registration.setOrder(1);
        return registration;
    }
}

测试:

 

2.基于注解的方式

  这种方式只需要在过滤器加上注解@WebFilter即可。过滤器的执行顺序是按照类名的字母顺序进行过滤。这种方式需要在springboot的运行类增加@ServletComponentScan注解。ServletComponentScan注解的为了Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码

package cn.qs;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
// Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。
@ServletComponentScan("cn")
public class MySpringBootApplication {
    public static void main(String[] args) {
        // 入口运行类
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

 

package cn.qlq.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

/**
 * 注解配置的filter执行顺序按类名的顺序执行
 */
@WebFilter(filterName = "myFilter", urlPatterns = "/*")
public class MyFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("=========enter filter===========");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

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

    }

}

 

package cn.qlq.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(filterName = "myFilter2", urlPatterns = "/*")
public class MyFilter2 implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("=========enter filter (MyFilter2)===========");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

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

    }

}

测试:

补充:还有另一种注册的方式,直接将filter 注入到Spring 

  这时候Spring 会采用一些默认的配置,比如filterName 采用的是bean的名称;默认拦截的url 是/*。 比如:

package com.zd.bx.filter;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class MyFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        System.out.println("com.zd.bx.filter.MyFilter.doFilter");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }

}

容器启动过程中:

1. 调用org.springframework.boot.web.servlet.ServletContextInitializerBeans#addAdaptableBeans 

    protected void addAdaptableBeans(ListableBeanFactory beanFactory) {
        MultipartConfigElement multipartConfig = this.getMultipartConfig(beanFactory);
        this.addAsRegistrationBean(beanFactory, Servlet.class, new ServletContextInitializerBeans.ServletRegistrationBeanAdapter(multipartConfig));
        this.addAsRegistrationBean(beanFactory, Filter.class, new ServletContextInitializerBeans.FilterRegistrationBeanAdapter());
        Iterator var3 = ServletListenerRegistrationBean.getSupportedTypes().iterator();

        while(var3.hasNext()) {
            Class<?> listenerType = (Class)var3.next();
            this.addAsRegistrationBean(beanFactory, EventListener.class, listenerType, new ServletContextInitializerBeans.ServletListenerRegistrationBeanAdapter());
        }

    }

2. org.springframework.boot.web.servlet.ServletContextInitializerBeans#addAsRegistrationBean(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>, java.lang.Class<B>, org.springframework.boot.web.servlet.ServletContextInitializerBeans.RegistrationBeanAdapter<T>) 

    private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type, Class<B> beanType, ServletContextInitializerBeans.RegistrationBeanAdapter<T> adapter) {
        List<Entry<String, B>> entries = this.getOrderedBeansOfType(beanFactory, beanType, this.seen);
        Iterator var6 = entries.iterator();

        while(var6.hasNext()) {
            Entry<String, B> entry = (Entry)var6.next();
            String beanName = (String)entry.getKey();
            B bean = entry.getValue();
            if (this.seen.add(bean)) {
                RegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());
                int order = this.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=" + this.getResourceDescription(beanName, beanFactory));
                }
            }
        }

    }

    private <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type, Set<?> excludes) {
        String[] names = beanFactory.getBeanNamesForType(type, true, false);
        Map<String, T> map = new LinkedHashMap();
        String[] var6 = names;
        int var7 = names.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            String name = var6[var8];
            if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {
                T bean = beanFactory.getBean(name, type);
                if (!excludes.contains(bean)) {
                    map.put(name, bean);
                }
            }
        }

        List<Entry<String, T>> beans = new ArrayList(map.entrySet());
        beans.sort((o1, o2) -> {
            return AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue());
        });
        return beans;
    }

1》这里获取到所有的filter, 然后创建RegistrationBean。

2》然后获取order,并且设置order。

    protected int getOrder(@Nullable Object obj) {
        if (obj != null) {
            Integer order = this.findOrder(obj);
            if (order != null) {
                return order;
            }
        }

        return 2147483647;
    }

3》添加到initializers 属性中

关于其默认的拦截路径是:org.springframework.boot.web.servlet.AbstractFilterRegistrationBean#DEFAULT_URL_MAPPINGS

private static final String[] DEFAULT_URL_MAPPINGS = new String[]{"/*"};

 

==============2.拦截器的使用==================

   拦截器的使用方法是先编写拦截器,然后注册到spring。拦截器的执行顺序是按照其注册顺序拦截。

package cn.qlq.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor1 implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {

        System.out.println("被 MyInterceptor1  postHandle拦截,放行...");
        return true;

    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv)
            throws Exception {
        System.out.println("被 MyInterceptor1 postHandle 拦截,放行...");
    }

    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行 (主要是用于进行资源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
            throws Exception {
        System.out.println("被 MyInterceptor1 afterCompletion 拦截,放行...");
    }
}

 

package cn.qlq.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor2 implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用(Controller方法调用之前)
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {

        System.out.println("被 MyInterceptor2  postHandle拦截,放行...");
        return true;

    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv)
            throws Exception {
        System.out.println("被 MyInterceptor2 postHandle 拦截,放行...");
    }

    /**
     * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行 (主要是用于进行资源清理工作)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
            throws Exception {
        System.out.println("被 MyInterceptor2 afterCompletion 拦截,放行...");
    }
}

 

注册到spring中:

package cn.qlq.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import cn.qlq.interceptor.MyInterceptor1;
import cn.qlq.interceptor.MyInterceptor2;

/**
 * 注册拦截器
 * 
 * @author Administrator
 *
 */
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * 拦截器按照顺序执行
         */
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/th/**").addPathPatterns("/freemarker/**");
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/freemarker/**");

        super.addInterceptors(registry);
    }

}

 

=============3.监听器的使用=================

  监听器的使用与过滤器使用差不多,也是先编写监听器,然后注入到spring中。

package cn.qlq.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MyHttpSessionListener implements HttpSessionListener {

    public static int online = 0;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("创建session,在线用户数:" + (++online));
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("销毁session,在线用户数:" + (--online));
        online--;
    }
}

 

package cn.qlq.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("容器创建");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("容器销毁");
    }

}

 

注入到spring中:

package cn.qlq.config;

import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import cn.qlq.listener.MyHttpSessionListener;
import cn.qlq.listener.MyServletContextListener;

/**
 * 
 * @author Administrator
 *
 */
@Configuration
public class ListenerConfig {
    @Bean
    public ServletListenerRegistrationBean<MyHttpSessionListener> listenerRegist() {
        ServletListenerRegistrationBean<MyHttpSessionListener> srb = new ServletListenerRegistrationBean<MyHttpSessionListener>();
        srb.setListener(new MyHttpSessionListener());
        return srb;
    }

    @Bean
    public ServletListenerRegistrationBean<MyServletContextListener> listenerRegist2() {
        ServletListenerRegistrationBean<MyServletContextListener> srb = new ServletListenerRegistrationBean<MyServletContextListener>();
        srb.setListener(new MyServletContextListener());
        return srb;
    }

}

测试:

 

补充:当然监听器可以使用注解方式,如下:

package cn.qs.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class StartListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("容器启动");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("容器销毁");
    }

}

 

=============4.Servlet的使用=================

  这里研究基于SpringMVC 提供的注册器。 

1. Servlet

package cn.xm.servlet;

import javax.servlet.*;
import java.io.IOException;

// 也可以用注解注入
//@WebServlet
public class MyServlet implements Servlet {

    public MyServlet() {
        System.out.println("MyServlet~~~~~~~~~~~ create");
    }

    @Override
    public void init(ServletConfig config) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("cn/xm/servlet/MyServlet.java:23    service~~~~~~");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

2. 注册:

package cn.xm.servlet;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyServletConfig {

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new MyServlet(), "/myservlet");
        servletRegistrationBean.addInitParameter("param1", "value1");
        return servletRegistrationBean;
    }
}

3. 查看源码

Spring 提供了一个注册接口org.springframework.boot.web.servlet.ServletContextInitializer

public interface ServletContextInitializer {

    void onStartup(ServletContext servletContext) throws ServletException;

}

org.springframework.boot.web.servlet.RegistrationBean 是一个抽象类,实现了上面接口,并实现了一些基本的方法,其子类有:分别对应不同的注册器

 org.springframework.boot.web.servlet.ServletRegistrationBean 继承自上面类RegistrationBean,源码如下:

public class ServletRegistrationBean extends RegistrationBean {

    private static final Log logger = LogFactory.getLog(ServletRegistrationBean.class);

    private static final String[] DEFAULT_MAPPINGS = { "/*" };

    private Servlet servlet;

    private Set<String> urlMappings = new LinkedHashSet<String>();

    private boolean alwaysMapUrl = true;

    private int loadOnStartup = -1;

    private MultipartConfigElement multipartConfig;

    /**
     * Create a new {@link ServletRegistrationBean} instance.
     */
    public ServletRegistrationBean() {
    }

    /**
     * Create a new {@link ServletRegistrationBean} instance with the specified
     * {@link Servlet} and URL mappings.
     * @param servlet the servlet being mapped
     * @param urlMappings the URLs being mapped
     */
    public ServletRegistrationBean(Servlet servlet, String... urlMappings) {
        this(servlet, true, urlMappings);
    }

    /**
     * Create a new {@link ServletRegistrationBean} instance with the specified
     * {@link Servlet} and URL mappings.
     * @param servlet the servlet being mapped
     * @param alwaysMapUrl if omitted URL mappings should be replaced with '/*'
     * @param urlMappings the URLs being mapped
     */
    public ServletRegistrationBean(Servlet servlet, boolean alwaysMapUrl,
            String... urlMappings) {
        Assert.notNull(servlet, "Servlet must not be null");
        Assert.notNull(urlMappings, "UrlMappings must not be null");
        this.servlet = servlet;
        this.alwaysMapUrl = alwaysMapUrl;
        this.urlMappings.addAll(Arrays.asList(urlMappings));
    }

    /**
     * Returns the servlet being registered.
     * @return the servlet
     */
    protected Servlet getServlet() {
        return this.servlet;
    }

    /**
     * Sets the servlet to be registered.
     * @param servlet the servlet
     */
    public void setServlet(Servlet servlet) {
        Assert.notNull(servlet, "Servlet must not be null");
        this.servlet = servlet;
    }

    /**
     * Set the URL mappings for the servlet. If not specified the mapping will default to
     * '/'. This will replace any previously specified mappings.
     * @param urlMappings the mappings to set
     * @see #addUrlMappings(String...)
     */
    public void setUrlMappings(Collection<String> urlMappings) {
        Assert.notNull(urlMappings, "UrlMappings must not be null");
        this.urlMappings = new LinkedHashSet<String>(urlMappings);
    }

    /**
     * Return a mutable collection of the URL mappings for the servlet.
     * @return the urlMappings
     */
    public Collection<String> getUrlMappings() {
        return this.urlMappings;
    }

    /**
     * Add URL mappings for the servlet.
     * @param urlMappings the mappings to add
     * @see #setUrlMappings(Collection)
     */
    public void addUrlMappings(String... urlMappings) {
        Assert.notNull(urlMappings, "UrlMappings must not be null");
        this.urlMappings.addAll(Arrays.asList(urlMappings));
    }

    /**
     * Sets the {@code loadOnStartup} priority. See
     * {@link ServletRegistration.Dynamic#setLoadOnStartup} for details.
     * @param loadOnStartup if load on startup is enabled
     */
    public void setLoadOnStartup(int loadOnStartup) {
        this.loadOnStartup = loadOnStartup;
    }

    /**
     * Set the {@link MultipartConfigElement multi-part configuration}.
     * @param multipartConfig the multi-part configuration to set or {@code null}
     */
    public void setMultipartConfig(MultipartConfigElement multipartConfig) {
        this.multipartConfig = multipartConfig;
    }

    /**
     * Returns the {@link MultipartConfigElement multi-part configuration} to be applied
     * or {@code null}.
     * @return the multipart config
     */
    public MultipartConfigElement getMultipartConfig() {
        return this.multipartConfig;
    }

    /**
     * Returns the servlet name that will be registered.
     * @return the servlet name
     */
    public String getServletName() {
        return getOrDeduceName(this.servlet);
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        Assert.notNull(this.servlet, "Servlet must not be null");
        String name = getServletName();
        if (!isEnabled()) {
            logger.info("Servlet " + name + " was not registered (disabled)");
            return;
        }
        logger.info("Mapping servlet: '" + name + "' to " + this.urlMappings);
        Dynamic added = servletContext.addServlet(name, this.servlet);
        if (added == null) {
            logger.info("Servlet " + name + " was not registered "
                    + "(possibly already registered?)");
            return;
        }
        configure(added);
    }

    /**
     * Configure registration settings. Subclasses can override this method to perform
     * additional configuration if required.
     * @param registration the registration
     */
    protected void configure(ServletRegistration.Dynamic registration) {
        super.configure(registration);
        String[] urlMapping = this.urlMappings
                .toArray(new String[this.urlMappings.size()]);
        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);
        }
    }

}

   核心是在onStartup 方法,前面都是在准备以及验证数据,真正的注册是在这里。这里也是用ServletContext.addServlet  动态注册Servlet,然后configure 方法设置匹配的URI。

 

  这个方法的调用过程是在启动时IoC容器创建完成方法org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#onRefresh调用方法

org.springframework.boot.context.embedded.EmbeddedWebApplicationContext#createEmbeddedServletContainer 内。

 

posted @ 2019-02-20 22:10  QiaoZhi  阅读(1163)  评论(0编辑  收藏  举报