1.根据web容器的SPI机制,web容器启动加载spring-web下的文件,META-INF\services\javax.servlet.ServletContainerInitializer
部分源码
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
2.读取并调用实现了WebApplicationInitializer接口的类
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.lang.Nullable;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{SpringContainer.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{MvcContainer.class};
}
//获取DispatcherServlet的映射信息
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//自定义filter
@Override
protected Filter[] getServletFilters() {
MyFilter myFilter = new MyFilter();
CorsFilter corsFilter = new CorsFilter();
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[]{myFilter/*,corsFilter*/, characterEncodingFilter};
}
@Override
protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) {
return super.registerServletFilter(servletContext, filter);
}
@Nullable
protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() {
return null;
}
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
//不扫描有@Controller注解的类
@ComponentScan(value = "com.andy.xxx",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
/*,@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {AppConfig.class})*/
})
public class SpringContainer {
}
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@ComponentScans
({@ComponentScan(value = "com.andy.xxx",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)/*,@ComponentScan(basePackageClasses = AppConfig.class)*/})
public class MvcContainer {
}
3.register ContextLoaderListener和DispatcherServlet
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
/**
* The default servlet name. Can be customized by overriding {@link #getServletName}.
*/
public static final String DEFAULT_SERVLET_NAME = "dispatcher";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);
}
4.启动springmvc功能,加入@EnableWebMvc会import类DelegatingWebMvcConfiguration,会加重springmvc的组件类
@Configuration
@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Autowired
private ApplicationContext applicationContext;
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setTemplateLoaderPath("classpath:/ftl/");
freeMarkerConfigurer.setDefaultEncoding("UTF-8");
freeMarkerConfigurer.setConfigLocation(applicationContext.getResource("classpath:ftl/ftl.properties"));
return freeMarkerConfigurer;
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker();
registry.jsp("/jsp/", ".jsp");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/view/ok").setViewName("ok");
registry.addViewController("/view/index").setViewName("index");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// configurer.enable();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor).addPathPatterns("/user/**").excludePathPatterns("/user/query/**");
registry.addInterceptor(new UserInterceptor1()).addPathPatterns("/user/**").excludePathPatterns("");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// registry.addResourceHandler("/image/**")
// .addResourceLocations("classpath:/img/");
}
/* @Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/user/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")
.maxAge(3600);
}*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// converters.add(new FastJsonHttpMessageConverter());
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//设置日期格式
ObjectMapper objectMapper = new ObjectMapper();
SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd");
objectMapper.setDateFormat(smt);
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
//设置中文编码格式
List<MediaType> list = new ArrayList<MediaType>();
list.add(MediaType.APPLICATION_JSON);
mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list);
converters.add(mappingJackson2HttpMessageConverter);
}
}