详细的点,都写到了注释里了。简单介绍一下下面的自定义的配置类
继承于Spring的AbstractAnnotationConfigDispatcherServletInitializer,至于Spring怎么接入tomcat的,可以参考Servlet API。
当然,代码的注释中也有一部分说明。
package com.evan.demo.configure;
import com.evan.demo.web.servlet.MyServlet;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.*;
import java.nio.charset.StandardCharsets;
/**
* 最顶层接口是org.springframework.web.WebApplicationInitializer
* 而他是由SpringServletContainerInitializer接入tomcat的,该类实现了
* javax.servlet.ServletContainerInitializer(@see Servlet API 3.x)
* 该接口实际上相当于web.xml的配置改为JavaConfig方式。
*
* SpringServletContainerInitializer会调用所有继承于WebApplicationInitializer的类
* 并执行其初始化方法。但要切记,该初始化为WEB容器级别的。
*/
public class DefaultWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// Spring IoC容器配置, 也就是spring的配置文件applicationContext.xml的事。
// 该配置负责初始化Spring父上下文,并且注册到ServletContext
// 通常除了controller,其他spring管理的组件如Service,Dao等等都会由它负责管理。
// spring查找bean的顺序是先在当前上下文中找,找不到再到父上下文找。
// 而dispatchServlet的上下文的父上下文就是这里配置的全局上下文。
return new Class<?>[]{DefaultRootInitializer.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
// DispatcherServlet的配置,相当于dispatch-servlet.xml
return new Class<?>[]{DefaultWebConfigure.class};
}
@Override
protected String[] getServletMappings() {
// DispatchServlet拦截请求匹配
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
HiddenHttpMethodFilter fl = new HiddenHttpMethodFilter();
return new Filter[]{fl};
}
/**
* 这个方法会在加载Spring的上下文之前执行,因为这个方法是在监听到应用启动的时候就执行了
* 所以在这里是无法获取spring上下文的
* WebApplicationInitializer对应用的初始化,早于监听器ContextLoaderListener的初始化
* @param servletContext
* @throws ServletException
*/
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 1. 调用getRootConfigClasses创建AnnotationConfigWebApplicationContext
// (因为是用注解配置的,当然会对应注解上下文),并作为入参。
// 创建ContextLoaderListener并注册到servletContext,该监听器会监听WEB应用的生命周期。
// 注意:这里还没有将全局上下文注册到WEB容器
// 2. 调用getServletConfigClasses获取DispatchServlet上下文的配置文件,
// 创建AnnotationConfigWebApplicationContext并注册当前的配置实例
// 3. 创建dispatcherServlet,并持有步骤2的上下文,
// 注意:这里还没有将全局上下文注册到WEB容器
// 4. 调用getServletMappings,配置指定拦截的URL
// 5. 调用getServletFilters,配置过滤器,并注册到WEB容器。这说明该配置的过滤器为WEB容器级别
/**
* ContextLoaderListener负责初始化父上下文,初始化后注册到WEB容器。当然是在本方法执行完成之后,在tomcat层
* 的应用启动事件发布后被调用ContextLoaderListener的contextInitialized方法中调用context.refresh完成的。
* 而dispatchServlet的上下文是在servlet的init方法初始化的,先设置父上下文,随后加载扫描注解完成上下文的初始化,
* 然后注册到servletContext。init方法同样是tomcat调用的。tomcat就是servlet容器,管理servlet生命周期自然不在话下。
*/
super.onStartup(servletContext);
// 配置其他的 servlet 和 filter
FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
encodingFilter.setInitParameter("encoding", String.valueOf(StandardCharsets.UTF_8));
encodingFilter.setInitParameter("forceEncoding", "true");
encodingFilter.addMappingForUrlPatterns(null, false, "/*");
// 此配置等价于在该类上注解@WebServlet(name = "myServlet", urlPatterns = "/servlet/*")
// 但是需要注意,这里是直接使用servletAPI的,即直接注册到ServletContext
// 因为不会像Controller/DispatchServlet那样被Spring管理起来
ServletRegistration.Dynamic myServlet =
servletContext.addServlet("myServlet", new MyServlet());
myServlet.setLoadOnStartup(10);
myServlet.addMapping("/servlet/*");
}
}