Back to Javatutorial

SpringBootWeb应用(一):Servlet组件的注册流程

docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(一):servlet组件的注册流程.md

1.0.019.2 KB
Original Source

springboot УҪע servlet servlet``filter``listenerôأspringboot ĵΪṩ 3 ַľ 3 ַԴʵ֡

1. ע᷽ʽ

1.1 ʹ XxxRegistrationBean ע

springboot ṩ͵ RegistrationBean servlet עᣬֱ ServletRegistrationBean``FilterRegistrationBean``ServletListenerRegistrationBeanǼʾǵ÷

/**
 * ׼һservlet
 */
public class MyServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // һЩ
        ...
    }
}

/**
 * ע
 */
@Bean
public ServletRegistrationBean registerServlet() {
    ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
            new MyServlet(), "/myServlet");
    // һЩò
    servletRegistrationBean.setXxx();
    ...
    return servletRegistrationBean;
}

servlet ע᷽ʽҪע filter``listenerֻʹöӦ RegistrationBean ɣͲչʾˡ

1.2 ʹ servlet עע

Servlet 3.0servlet ṩ 3 ע servlet ע᣺

  • @WebServlet: servlet ע
  • @WebFilter: filter ע
  • @WebListener: listener ע

servlet עΪ @WebServlet:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
    String name() default "";

    String[] value() default {};

    String[] urlPatterns() default {};

    int loadOnStartup() default -1;

    WebInitParam[] initParams() default {};

    boolean asyncSupported() default false;

    String smallIcon() default "";

    String largeIcon() default "";

    String description() default "";

    String displayName() default "";
}

Կ@WebServlet ֶ֧ãָ servlet ơӳ url ָҲṩһʾ

@WebServlet(name = "myServlet", urlPatterns = "/myServlet")
public class JavaServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // һЩ
        ...
    }

}

󣬻ҪһҪIJǾʹ @ServletComponentScan ɨ蹦ܣ

// ʹ @ServletComponentScan  servlet ɨ蹦
@ServletComponentScan
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        ...
    }
}

1.3 ServletContextInitializer ע

ʹַʽעᣬҪʵ ServletContextInitializer ӿڣ

/**
 * ׼һservlet
 */
public class MyServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // һЩ
        ...
    }
}

/**
 * ʵ ServletContextInitializer 
 */
@Component
public class ServletConfig implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext servletContext) {
        // ʹ servletContext ע
        ServletRegistration initServlet = servletContext.addServlet("myServlet", MyServlet.class);
        // ԽһЩ
        initServlet.addMapping("/myServlet");
    }

}

ʹַʽעᣬҪʵ ServletContextInitializerȻд ServletContextInitializer#onStartup ServletContextInitializer#onStartup ʹ ServletContext עᡣServletContext servlet ṩעռ࣬ʹ RegistrationBean עᣬʹ @ServletComponentScan ɨעᣬնͨ ServletContext עᵽ servlet С

2. Դʵ

˽ʹú󣬽Ǿ Դ뿴Щʵ֡

2.1 @ServletComponentScan ɨ

ֱӽ @ServletComponentScan

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {
    ...
}

ע @Import ע⣬һࣺServletComponentScanRegistrarǿ྿ɶ

/**
 * ʵImportBeanDefinitionRegistrar
 * ע ServletComponentRegisteringPostProcessor
 */
class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    private static final String BEAN_NAME = "servletComponentRegisteringPostProcessor";

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 
            BeanDefinitionRegistry registry) {
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
        if (registry.containsBeanDefinition(BEAN_NAME)) {
            updatePostProcessor(registry, packagesToScan);
        }
        else {
            // ע BeanFactoryPostProcessor
            addPostProcessor(registry, packagesToScan);
        }
    }

    /**
     * ע BeanFactoryPostProcessor
     * ע ServletComponentRegisteringPostProcessor
     */
    private void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        // ServletComponentRegisteringPostProcessor: ɨ BeanFactoryPostProcessor
        beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packagesToScan);
        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // ServletComponentScanRegistrar Ϊע ServletComponentRegisteringPostProcessor
        registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
    }

    ...

}

Կʵ ImportBeanDefinitionRegistrarҪ spring ע ServletComponentRegisteringPostProcessorǼȥ ServletComponentRegisteringPostProcessor

class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor, 
        ApplicationContextAware {

    /**
     * Ҫɨİ.
     */
    private final Set<String> packagesToScan;

    /**
     * Ҫɨİɹ췽
     */
    ServletComponentRegisteringPostProcessor(Set<String> packagesToScan) {
        this.packagesToScan = packagesToScan;
    }

    /**
     * дBeanFactoryPostProcessorķ
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
            throws BeansException {
        // жǷǶ web 
        if (isRunningInEmbeddedWebServer()) {
            // ɨɨ
            ClassPathScanningCandidateComponentProvider componentProvider 
                    = createComponentProvider();
            for (String packageToScan : this.packagesToScan) {
                // аɨ
                scanPackage(componentProvider, packageToScan);
            }
        }
    }

    ...

}

ԿServletComponentRegisteringPostProcessor ʵ BeanFactoryPostProcessorд BeanFactoryPostProcessor#postProcessBeanFactory дɨɨǰǴɨ ClassPathScanningCandidateComponentProviderȻٽɨ衣

ɨĴ createComponentProvider()

//  handler
private static final List<ServletComponentHandler> HANDLERS;

static {
    List<ServletComponentHandler> servletComponentHandlers = new ArrayList<>();
    servletComponentHandlers.add(new WebServletHandler());
    servletComponentHandlers.add(new WebFilterHandler());
    servletComponentHandlers.add(new WebListenerHandler());
    HANDLERS = Collections.unmodifiableList(servletComponentHandlers);
}

/**
 * ɨ
 */
private ClassPathScanningCandidateComponentProvider createComponentProvider() {
    // 
    ClassPathScanningCandidateComponentProvider componentProvider 
            = new ClassPathScanningCandidateComponentProvider(false);
    componentProvider.setEnvironment(this.applicationContext.getEnvironment());
    componentProvider.setResourceLoader(this.applicationContext);
    for (ServletComponentHandler handler : HANDLERS) {
        // ù˹
        componentProvider.addIncludeFilter(handler.getTypeFilter());
    }
    return componentProvider;
}

createComponentProvider() УǴɨȻһЩԣžù˹ص¹˹ãЩ WebServletHandler/WebFilterHandler/WebListenerHandler getTypeFilter()

getTypeFilter() λһ󷽷У

abstract class ServletComponentHandler {

    private final TypeFilter typeFilter;

    /**
     * ע⣬תΪ AnnotationTypeFilter 
     */
    protected ServletComponentHandler(Class<? extends Annotation> annotationType) {
        this.typeFilter = new AnnotationTypeFilter(annotationType);
        ...
    }

    /**
     *  TypeFilter
     */
    TypeFilter getTypeFilter() {
        return this.typeFilter;
    }
    ...
}

ServletComponentHandler УһԱ typeFilterڹ췽дעֵת AnnotationTypeFilterȻֵ typeFilter getTypeFilter() صľ typeFilter

˽ typeFilter Դļʵࣺ

/**
 * WebFilterHandler 췽IJ WebFilter
 */
class WebFilterHandler extends ServletComponentHandler {
    WebFilterHandler() {
        super(WebFilter.class);
    }
    ...
}

/**
 * WebListenerHandler 췽IJ WebListener
 */
class WebListenerHandler extends ServletComponentHandler {
    WebListenerHandler() {
        super(WebListener.class);
    }
    ...
}

/**
 * WebServletHandler 췽IJ WebServlet
 */
class WebServletHandler extends ServletComponentHandler {
    WebServletHandler() {
        super(WebServlet.class);
    }
    ...
}

ɴ˾ˣcreateComponentProvider() õ ClassPathScanningCandidateComponentProvider ֻ 3 עࣺ

  • @WebFilter
  • @WebListener
  • @WebServlet

Ǽɨ̣Ϊ ServletComponentRegisteringPostProcessor#scanPackage:

private void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider, 
        String packageToScan) {
    for (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {
        if (candidate instanceof AnnotatedBeanDefinition) {
            // õ BeanDefinition
            for (ServletComponentHandler handler : HANDLERS) {
                handler.handle(((AnnotatedBeanDefinition) candidate),
                        (BeanDefinitionRegistry) this.applicationContext);
            }
        }
    }
}

ھɨ̣ClassPathScanningCandidateComponentProvider#findCandidateComponents ͬ spring İɨ̻һ£Ͳչϸˣǰص BeanDefinition ĴϣҲ ServletComponentHandler#handle

void handle(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
    //  annotationType ǹ췽дע⣬@WebFilter@WebListener 
    Map<String, Object> attributes = beanDefinition.getMetadata()
            .getAnnotationAttributes(this.annotationType.getName());
    // ж϶ӦעǷڣ
    if (attributes != null) {
        doHandle(attributes, beanDefinition, registry);
    }
}

ڴɨõ BeanDefinition ʱȱе handler(WebServletHandler/WebFilterHandler/WebListenerHandlerServletComponentHandler#handle д ServletComponentHandler#handle УֻǷڶӦעǷڣʹ AnnotatedBeanDefinition#getMetadata ȡӦעϢǷ doHandler()

ô doHandler() ʲôأǽ WebServletHandler#doHandle

public void doHandle(Map<String, Object> attributes, AnnotatedBeanDefinition beanDefinition,
        BeanDefinitionRegistry registry) {
    // ע ServletRegistrationBean Ӧ BeanDefinition
    BeanDefinitionBuilder builder = BeanDefinitionBuilder
            .rootBeanDefinition(ServletRegistrationBean.class);
    builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
    builder.addPropertyValue("initParameters", extractInitParameters(attributes));
    builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));
    // ȡ servlet ƣָƣʹָƣûָʹbean
    String name = determineName(attributes, beanDefinition);
    builder.addPropertyValue("name", name);
    builder.addPropertyValue("servlet", beanDefinition);
    builder.addPropertyValue("urlMappings", extractUrlPatterns(attributes));
    builder.addPropertyValue("multipartConfig", determineMultipartConfig(beanDefinition));
    registry.registerBeanDefinition(name, builder.getBeanDefinition());
}

ԿҪǴ Servlet ã spring ע ServletRegistrationBean Ӧ beanDefinition

Handler doHandle() Ҳ࣬ spring ע beanDefinition ͬͲϸˡ

ܽ⼸ע spring ע beanDefinition

  • @WebServlet: ע ServletRegistrationBean Ӧ beanDefinition
  • @WebFilter: ע FilterRegistrationBean Ӧ beanDefinition
  • @WebListener: ע ServletListenerRegistrationBean Ӧ beanDefinition

ʹ XxxRegistrationBean עʱֶ XxxRegistrationBeanȻͨ @Bean עעᵽ spring Уʹ @WebServlet/@WebFilter/@WebListener һȦҲǻص XxxRegistrationBean

2.2 XxxRegistrationBean ע

ʹ XxxRegistrationBean עᣬʹ @ServletComponentScan ɨעᣬնõ XxxRegistrationBean Ӧ beanǾ̽Щ bean עᵽ servlet еġ

ӴϿServletRegistrationBean``FilterRegistrationBean ServletListenerRegistrationBean ServletContextInitializer ӿڵʵ࣬ServletRegistrationBean ļ̳нṹ£

ServletContextInitializer ֻһ onStartup(...)

@FunctionalInterface
public interface ServletContextInitializer {

    /**
     *  servletContextǽ Servletfilterlistener ע
     */
    void onStartup(ServletContext servletContext) throws ServletException;

}

ڽ servlet ע᷽ʽʱᵽͨʵ ServletContextInitializerд onStartup() ʵ servlet עᣬ XxxRegistrationBean ĵײʵҲôġ

ServletRegistrationBean onStartup(...) ɶ

ServletRegistrationBean ûд onStartup(...) ֱӼ̳ RegistrationBean:

public final void onStartup(ServletContext servletContext) throws ServletException {
    // ȡϢ 
    String description = getDescription();
    // ǷעᣬĬΪtrue
    if (!isEnabled()) {
        logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
        return;
    }
    // ע
    register(description, servletContext);
}

ӣȻȡһϢȻжǷעᣬžǽעˡֱӲ鿴ע DynamicRegistrationBean#register:

protected final void register(String description, ServletContext servletContext) {
    D registration = addRegistration(description, servletContext);
    if (registration == null) {
        logger.info(...);
        return;
    }
    // 
    configure(registration);
}

Ҫ£ע servlet 봦ãע ServletRegistrationBean#addRegistration :

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

עDZȽϼ򵥵ģֱӵ ServletContext#addServlet С

鿴ô ServletRegistrationBean#configure

protected void configure(ServletRegistration.Dynamic registration) {
    // ø
    super.configure(registration);
    // urlMapping
    String[] urlMapping = StringUtils.toStringArray(this.urlMappings);
    if (urlMapping.length == 0 && this.alwaysMapUrl) {
        urlMapping = DEFAULT_MAPPINGS;
    }
    if (!ObjectUtils.isEmpty(urlMapping)) {
        registration.addMapping(urlMapping);
    }
    // loadOnStartup
    registration.setLoadOnStartup(this.loadOnStartup);
    // һЩ
    if (this.multipartConfig != null) {
        registration.setMultipartConfig(this.multipartConfig);
    }
}

ǵ˸ķȻôˣҪǴ urlMapping loadOnStartupͲˡ

super.configure(...) ɶ DynamicRegistrationBean#configure:

/**
 * ҲǴһЩ
 */
protected void configure(D registration) {
    registration.setAsyncSupported(this.asyncSupported);
    // óʼ
    if (!this.initParameters.isEmpty()) {
        registration.setInitParameters(this.initParameters);
    }
}

Ҫ˳ʼá

ķServletRegistrationBean onStartup(...) Ҫ

  1. servlet ӵ
  2. servlet

FilterRegistrationBean ServletListenerRegistrationBean עƣͲ˵ˡ

2.3 ServletContextInitializer#onStartup ִ

עѾˣ ServletContextInitializer#onStartup ִеġעһ̱Ƚϸӣ漰 tomcat ̣ⲿֻעص룬һ̡

tomcat Ϊһϵеĵ׷٣ TomcatStarter еģ£

class TomcatStarter implements ServletContainerInitializer {

    private final ServletContextInitializer[] initializers;

    TomcatStarter(ServletContextInitializer[] initializers) {
        this.initializers = initializers;
    }

    @Override
    public void onStartup(Set<Class<?>> classes, ServletContext servletContext) 
            throws ServletException {
        try {
            for (ServletContextInitializer initializer : this.initializers) {
                // ִ ServletContextInitializer#onStartup
                initializer.onStartup(servletContext);
            }
        }
        catch (Exception ex) {
            this.startUpException = ex;
            ...
        }
    }

    ...

}

TomcatStarter springboot ṩ࣬ʵ ServletContainerInitializer ServletContextInitializer``ServletContainerInitializer tomcat ṩģ tomcat ʱִ ServletContainerInitializer#onStartup servlt 3.0

ô TomcatStarter ӵ tomcat еأȻ servlt 3.0 淶ͨ spi ɨ赽 ServletContainerInitializer ʵ֣ԲģΪ tomcat ͨ spi ɨõ TomcatStarter ʵijԱ initializers ޷ֵˣӵ tomcat ǰTomcatStarter Ҫʵ initializers Ҫֵ

εԣ TomcatStarter TomcatServletWebServerFactory#configureContext ӵ tomcat ģؼ:

ԿinitializersTomcatStarter Ĺ췽Уõ TomcatStarter ʵֶӵ tomcat ˡ

ô initializers ȡأʵϣǵ XxxRegistrationBean Ҫ spring УҪȡĻֻҪ beanFactory.getBeansOfType(...) ͿˣServletContextInitializerBeans#addServletContextInitializerBean(String, ServletContextInitializer, ListableBeanFactory) Ǹµģ

private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
    for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
        // ȡ ServletContextInitializer: getOrderedBeansOfType(beanFactory, initializerType)
        for (Entry<String, ? extends ServletContextInitializer> initializerBean 
                : getOrderedBeansOfType(beanFactory, initializerType)) {
            addServletContextInitializerBean(initializerBean.getKey(), 
                initializerBean.getValue(), beanFactory);
        }
    }
}

/**
 * Ӳ
 */
private void addServletContextInitializerBean(String beanName, 
        ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
    //  ServletRegistrationBean
    if (initializer instanceof ServletRegistrationBean) {
        Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
        addServletContextInitializerBean(Servlet.class, beanName, initializer, 
                beanFactory, source);
    }
    //  FilterRegistrationBean
    else if (initializer instanceof FilterRegistrationBean) {
        Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
        addServletContextInitializerBean(Filter.class, beanName, initializer, 
                beanFactory, source);
    }
    //  DelegatingFilterProxyRegistrationBean
    else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
        String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
        addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
    }
    //  ServletListenerRegistrationBean
    else if (initializer instanceof ServletListenerRegistrationBean) {
        EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
        addServletContextInitializerBean(EventListener.class, beanName, initializer, 
                beanFactory, source);
    }
    else {
        //  ServletContextInitializer Bean
        addServletContextInitializerBean(ServletContextInitializer.class, beanName, 
                initializer, beanFactory, initializer);
    }
}

3. ܽ

ķ springboot ע servlet ̣

  1. Servlet Ϊ 3 ע᷽ʽʹ XxxRegistrationBean עᡢʹ servlet ע (@WebServlet/@WebFilter/@WebListener) עᣬԼʵ ServletContextInitializer ӿֶע᣻
  2. @ServletComponentScan עɨ
  3. ServletRegistrationBean Ϊ˽ ServletRegistrationBean עᵽ servlet
  4. ServletContainerInitializer#onStartup ִ

ԭӣhttps://my.oschina.net/funcy/blog/4951050 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע