1、AnnotationConfigApplicationContext与AnnotationConfigWebApplicationContext
2、Spring如何解析@RequestMapping
3、web的自动配置
4、SpringMVC响应json数据
上一篇文章中说道DispatcherServlet会随着Tomcat容器启动,会调用DispatcherServlet的init初始化方法,在这个初始化方法中,这个servlet回去初始化spring的环境。
// FrameworkServlet#initServletBean
protected final void initServletBean() throws ServletException {
// 初始化web环境 WebApplicationContext ==child==> ConfigurableWebApplicationContext
this.webApplicationContext = initWebApplicationContext();
// 调用了initFrameworkServlet方法,这是一个空方法
initFrameworkServlet();
}
// FrameworkServlet#configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
// 设置ServletContext等属性
wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
// 添加了一个监听器,监听容器刷新完成事件 DispatcherServlet#onRefresh 初始化SpringMVC组件
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// refresh的前置处理 设置环境的servlet上下文和servletConfig
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
// 空方法
postProcessWebApplicationContext(wac);
// 调用容器的初始化方法 ApplicationContextInitializer#initialize接口的实现类
applyInitializers(wac);
// 刷新容器,走到AbstractApplicationContext中的refresh方法
wac.refresh();
}
调用了AbstractApplicationContext#refresh,在这个方法中AnnotationConfigWebApplicationContext的webContext重写了postProcessBeanFactory方法
// AbstractRefreshableWebApplicationContext#postProcessBeanFactory
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加了一个BeanPostProcessor
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
// 注册web环境
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
ServletContextAwareProcessor这个BeanPostProcessor会在init方法执行之前为ServletContextAware设置servletContext属性
// ServletContextAwareProcessor#postProcessBeforeInitialization
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware) bean).setServletContext(getServletContext());
}
if (getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware) bean).setServletConfig(getServletConfig());
}
return bean;
}
处理@RequestMapping
处理入口:RequestMappingHandlerMapping
从上图可以看出RequestMappingHandlerMapping实现了InitializingBean接口,而这个对象会在SpringMVC初始化的时候有Spring来创建。
// RequestMappingHandlerMapping#afterPropertiesSet
public void afterPropertiesSet() {
// 设置配置信息
this.config = new RequestMappingInfo.BuilderConfiguration();
// url路径解析工具 比如截取出uri ...
this.config.setUrlPathHelper(getUrlPathHelper());
// AntPathMatcher 路径匹配工具
this.config.setPathMatcher(getPathMatcher());
// 是否开启后缀匹配模式 默认true
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
// 是否开启尾部/ 匹配 默认true
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
// 父类 AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
// 遍历spring中所有的object beanName
for (String beanName : getCandidateBeanNames()) {
// 是否以 scopedTarget. 开头
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
// bean class
Class<?> beanType = obtainApplicationContext().getType(beanName);
if (beanType != null && isHandler(beanType)) {
// 筛选出Controller或者RequestMapping注解
detectHandlerMethods(beanName);
}
}
// 注意这里的isHandler判断
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
解析加了Controller或者RequestMapping注解的类
// AbstractHandlerMethodMapping#detectHandlerMethods handler就是传入的bean对象
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 筛选出请求方法 合并请求uri
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
return getMappingForMethod(method, userType);
});
// 注册方法映射
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
// 方法的解析
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 解析@RequestMapping 包括内部的各种属性 请求类型 映射路径 参数 ...
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 获取类上面的@RequestMapping注解
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// requestMapping合并
info = typeInfo.combine(info);
}
// 获取类上面的前缀
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
// 进行前缀合并
info = RequestMappingInfo.paths(prefix).build().combine(info);
}
}
return info;
}
注册Controller映射对应关系
// 方法映射的注册
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
// Controller中对方法的要求
public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
// 当前类的方法
Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
// 私有方法 + 非静态方法 + SpringProxy子类 -> SpringProxy子类的私有方法会直接抛出异常
if (Modifier.isPrivate(methodToUse.getModifiers())
&& !Modifier.isStatic(methodToUse.getModifiers())
&& SpringProxy.class.isAssignableFrom(targetType)) {
throw new IllegalStateException("xxxx");
}
}
// 映射的注册
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
注册的具体逻辑:AbstractHandlerMethodMapping.MappingRegistry#register
public void register(T mapping, Object handler, Method method) {
// 写锁
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
// 把 [mapping - handlerMethod] 放入mappingLookup
// mapping就是当前方法的汇总注解信息
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
// urlLookup中放入的是 [uri - mapping] {"/index",RequestMappingInfo}
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
// 解析其他形式的uri 正则 后缀 矩阵 等
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 缓存已注册的信息
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
} finally {
this.readWriteLock.writeLock().unlock();
}
}
@EnableWebMvc注解
@EnableWebMvc表示开启webmvc的自动配置,并且我们可以实现WebMvcConfigurer接口去添加SpringMVC的组件,比如:异常处理器、视图解析器、拦截器、消息转换器等等。
为什么我们实现并重写WebMvcConfigurer接口中的方法,spring就可以用到这些组件,就和这个注解有关。
spring在解决DelegatingWebMvcConfiguration的依赖时,回去容器中所有实现了WebMvcConfigurer接口的bean对象,返回注入到这里来。
源码参考:AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {}
// 导入的配置类
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// WebMvcConfigurerComposite实现了WebMvcConfigurer接口
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
// 为set方法注入配置集合
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
//省略很多方法
}
重点分析WebMvcConfigurerComposite类
class WebMvcConfigurerComposite implements WebMvcConfigurer {
// 配置类集合
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addInterceptors(registry);
}
}
}
在这个DelegatingWebMvcConfiguration类中只有一个@Bean,明显靠着一个bean对象是无法完成springmvc的,所以我们继续分析它的父类WebMvcConfigurationSupport。
// 这里面注入了很多的web组件 拦截器 异常处理器 视图解析器 处理器映射器 等等
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
// 主要看RequestMappingHandlerMapping
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// new RequestMappingHandlerMapping()
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
// 设置拦截器
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
// .... 很多组件
return mapping;
}
// 拦截器的获取逻辑
protected final Object[] getInterceptors() {
if (this.interceptors == null) {
// 拦截器注册器
InterceptorRegistry registry = new InterceptorRegistry();
// 向configurers中添加注册器,这里其实就是注册程序中自己写的拦截
addInterceptors(registry);
// 注册两个拦截器 这两个拦截器都会被包装为InterceptorRegistration
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
// 获取所有的拦截器(包括使用WebMvcConfigurer注册的)
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
}
当使用WebMvcConfigurer去添加拦截器的时候,拦截器会被包装为InterceptorRegistration。
// InterceptorRegistry#addInterceptor
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
this.registrations.add(registration);
return registration;
}
SpringMVC响应json数据
我们都知道,要使springMVC可以响应json数据,必须要添加一个消息转换器。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/index/2");
}
// 配置消息转换器
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jsonHttpMessageConverter());
}
@Bean
public FastJsonHttpMessageConverter jsonHttpMessageConverter() {
return new FastJsonHttpMessageConverter();
}
}
分析处理器处理请求的时候,以@RequestMapping为例,核心处理逻辑:RequestMappingHandlerAdapter#handleInternal
// RequestMappingHandlerAdapter的构造方法
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
// 添加了四个 messageConverter
this.messageConverters = new ArrayList<>(4);
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(stringHttpMessageConverter);
this.messageConverters.add(new SourceHttpMessageConverter<>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
处理请求的方法调用过程
RequestMappingHandlerAdapter#handleInternal
=> RequestMappingHandlerAdapter#invokeHandlerMethod
=> ServletInvocableHandlerMethod#invokeAndHandle
主要看ServletInvocableHandlerMethod#invokeAndHandle方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
// 调用了具体controller中的方法,获取了返回值
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 根据@ResponseStatus code 设置status
setResponseStatus(webRequest);
// 返回值为 null
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
// 检查@ResponseStatus注解的reason
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
// 标记请求是否处理完成
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 选择合适的结果处理器来处理结果集
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
结果处理器的选择
// HandlerMethodReturnValueHandlerComposite#handleReturnValue
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 获取一个可以处理 returnType 的结果集处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
// 如果找不到一个结果集处理器来处理,就会在这里抛出异常
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 调用 handleReturnValue 来处理结果
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
// HandlerMethodReturnValueHandlerComposite#selectHandler
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// 循环所有的结果处理器
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 如果找到一个可以处理这个结果类型的处理器,就直接将这个处理器返回 supportsReturnType
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
已知存在的结果处理器有以下几种
# 处理ModelAndView类型的返回值
ModelAndViewMethodReturnValueHandler
# 处理Model类型的返回值
ModelMethodProcessor
# 处理View类型的返回值
ViewMethodReturnValueHandler
# 处理ResponseBodyEmitter类型
ResponseBodyEmitterReturnValueHandler
# 处理StreamingResponseBody类型
StreamingResponseBodyReturnValueHandler
# 处理HttpEntity和RequestEntity类型
HttpEntityMethodProcessor
# 处理HttpHeaders类型
HttpHeadersReturnValueHandler
# 处理Callable类型
CallableMethodReturnValueHandler
# 处理DeferredResult ListenableFuture和CompletionStage类型
DeferredResultMethodReturnValueHandler
# 处理WebAsyncTask
AsyncTaskMethodReturnValueHandler
# 处理ModelAttribute
ModelAttributeMethodProcessor
# 处理加了 @RequestBody 注解的返回值
RequestResponseBodyMethodProcessor
# 处理没有添加 @RequestBody 并返回string类型的返回 会解析成视图名称
ViewNameMethodReturnValueHandler
# 处理map返回值
MapMethodProcessor
判定规则就是调用每一个处理器的supportsReturnType方法,来找到可以处理这个返回值类型的处理器。
如果我们添加了@RequestBody注解,那么就会进入RequestResponseBodyMethodProcessor处理器。
// RequestResponseBodyMethodProcessor#supportsReturnType
public boolean supportsReturnType(MethodParameter returnType) {
// 类或者方法上存在ResponseBody注解
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
// 调用 RequestResponseBodyMethodProcessor#handleReturnValue 方法处理返回值
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
// 标记为已处理
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
// 如果这个的返回值是void,那么会在 ResponseBodyAdvice 中处理
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
确定响应的类型,调用spring中所有的messageConverters进行处理。下面贴出关键代码
// AbstractMessageConverterMethodProcessor#writeWithMessageConverters
// InputStreamResource 或者 Resource 类型
if (isResourceType(value, returnType)) {
outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
}
MediaType contentType = outputMessage.getHeaders().getContentType();
// 遍历 messageConverters 来处理结果集
for (HttpMessageConverter<?> converter : this.messageConverters) {
// 最终调用 messageConverter 将结果集write出去 -> FastJsonHttpMessageConverter#write
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
// AbstractHttpMessageConverter#write t就是方法的返回值
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage) {
final HttpHeaders headers = outputMessage.getHeaders();
// 添加默认的头信息
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
// 调用FastJsonHttpMessageConverter#writeInternal
streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
@Override
public OutputStream getBody() {
return outputStream;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}));
}
}
最后就是使用一个ByteArrayOutputStream输出流将返回值写到HttpResponse的body中。