文章目录
- onRefresh刷新dispatcherservlet九大组件的主要地方
- initMultipartResolver 初始化文件上传解析器
- initLocaleResolver本地化解析
- getDefaultStrategy方法获取默认配置(缺省策略)
- initHandlerMappings处理器映射器 保存Url映射关系(重要)
- springmvc.xml配置的注解扫描
- HandlerMapping
- BeanNameUrlHandlerMapping详解
- RequestMappingHandlerMapping详解(通过@RequestMapping配置的类重要)
- HandlerAdapter
- SimpleControllerHandlerAdapter
- HttpRequestHandlerAdapter同理实现HttpRequestHandler接口的
- RequestMappingHandlerAdapter(重要)
在讲initWebApplicationContext方法的时候,分为两部分,一部分是创建web端的spring容器,一部分是DispatcherServlet的加载,前面一篇
onRefresh刷新dispatcherservlet九大组件的主要地方
onRefresh在frameworkservlet方法里是空的,在dispatcherservlet里重写了onRefresh方法,我们看dispatcherservlet里面的:
@Override
protected void onRefresh(ApplicationContext context) {
//初始化九大组件
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
// 初始化文件上传解析器
initMultipartResolver(context);
// 本地化解析
initLocaleResolver(context);
// 主题解析器
initThemeResolver(context);
// 处理器映射器 保存Url映射关系
initHandlerMappings(context);
// 处理器适配器
initHandlerAdapters(context);
// 异常解析器
initHandlerExceptionResolvers(context);
// 视图提取器,从request中获取viemName
initRequestToViewNameTranslator(context);
// 视图解析器
initViewResolvers(context);
// 参数解析器
initFlashMapManager(context);
}
初始这些组件的话,springmvc都有默认的配置,DispatcherServlet.properties;
初始化大体都是先从spring中获取,如果获取不到抛出了NoSuchBeanDefinitionException就走getDefaultStrategies方法从DispatcherServlet.properties中获取配置;大部分代码几乎都是相同的我就简单的讲几个其他都是换汤不换药
initMultipartResolver 初始化文件上传解析器
就是直接从spring容器中取,没取到就设置为空:
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
initLocaleResolver本地化解析
也是直接从spring容器中取,没取到就从默认配置中获取:
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
getDefaultStrategy方法获取默认配置(缺省策略)
这个方法就是从DispatcherServlet.properties;文件中获取默认配置,代码都很简单,就通过配置,将类通过反射初始化出来而已:
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
// 正在获取默认配置的地方
List<T> strategies = getDefaultStrategies(context, strategyInterface);
if (strategies.size() != 1) {
throw new BeanInitializationException(
"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
}
//返回第一个
return strategies.get(0);
}
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames) {
try {
// 通过反射将类初始化出来
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
return strategies;
}
else {
return new LinkedList<T>();
}
}
initThemeResolver主题解析器(略同上)
initHandlerMappings处理器映射器 保存Url映射关系(重要)
private void initHandlerMappings(ApplicationContext context) {
// 初始化记录 HandlerMapping 对象的属性变量为null
this.handlerMappings = null;
// 根据属性detectAllHandlerMappings决定是检测所有的 HandlerMapping 对象,还是
// 使用指定名称的 HandlerMapping 对象
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 从容器及其祖先容器查找所有类型为 HandlerMapping 的 HandlerMapping 对象,记录到 handlerMappings 并排序
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 排序,关于这里的排序,可以参考 WebMvcConfigurationSupport 类中对各种 HandlerMapping bean
// 进行定义时所使用的 order 属性,顺序属性很关键,因为它涉及到 HandlerMapping 使用时的优先级
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
// 获取名称为 handlerMapping 的 HandlerMapping bean 并记录到 handlerMappings
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
// 如果上面步骤从容器获取 HandlerMapping 失败,则使用缺省策略创建 HandlerMapping 对象记录到handlerMappings
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
到这里distpatcherservlet的初始化方法大部分都讲完了,这些方法跟上面三个差不多就不做过多描述了:
initHandlerAdapters 处理器适配器(同initHandlerMappings)
initHandlerExceptionResolvers 异常解析器(略)
initRequestToViewNameTranslator 视图提取器,从request中获取viemName(略)
initViewResolvers 视图解析器(略)
initFlashMapManager 参数解析器(略)
springmvc.xml配置的注解扫描
HandlerMapping
在springmvc的配置文件中,通常配置了注解扫描mvc:annotation-driven/,因为前面init是直接从spring容器中直接获取的,在这边配置就能获取到,而解析这个标签的类,里面注册了一些基本的handlermapping,主要有RequestMappingHandlerMapping ,RequestMappingHandlerAdapter ,ExceptionHandlerExceptionResolver ,
BeanNameUrlHandlerMapping
mvc:annotation-driven注解详解
<mvc:annotation-driven/>
BeanNameUrlHandlerMapping详解
首先看类图:
接口ApplicationContextAware是spring包下的,会注入spring容器,各种aware接口,前面讲spring源码的时候说过一次,这里就不做过多描述了;
我们就从ApplicationObjectSupport类的setApplicationContext方法入口看,没啥主要的,看一眼就知道,主要方法是initApplicationContext,然后就是调用AbstractDetectingUrlHandlerMapping的initApplicationContext方法:源码比较简单,主要就是将以/开头的beanName名称跟对应的beanname进行映射,注意是以/开头的bean
所以一般这个类不常用~
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
protected void detectHandlers() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
RequestMappingHandlerMapping详解(通过@RequestMapping配置的类重要)
首先看看类图,实现了InitializingBean接口,这个接口在spring容器加载完成的时候会执行afterPropertiesSet方法,而这个类主要入口也是这个方法:
RequestMappingHandlerMapping的afterPropertiesSet方法:
@Override
public void afterPropertiesSet() {
//用来保存RequestMapping注解里面的配置项
this.config = new RequestMappingInfo.BuilderConfiguration();
// path解析的类
this.config.setUrlPathHelper(getUrlPathHelper());
// path匹配
this.config.setPathMatcher(getPathMatcher());
// 前缀处理
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
// 是否开启PatternsRequestCondition中的尾随斜杠 默认true
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
// 是否开启后缀访问,方法上的/hello也会匹配到/hello.json路径 默认false
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
// 设置ProducesRequestCondition需要的内容管理器
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
然后调用父类的afterPropertiesSet方法,这个方法就调用initHandlerMethods方法:
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
// detectHandlerMethodsInAncestorContexts为false
// 获取web容器中所有的beanName,如果为true表示从父容器中也获取,就是springcontext中也获取
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
//遍历
for (String beanName : beanNames) {
// 如果beanName没有以SCOPED_TARGET_NAME_PREFIX = "scopedTarget."起始
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
// isHandler判断是否有Controller注解或者RequestMapping注解
if (beanType != null && isHandler(beanType)) {
// 加载对应handler所有的handlerMethod方法
detectHandlerMethods(beanName);
}
}
}
// handlerMethod加载完成后执行,留给子类去扩展
handlerMethodsInitialized(getHandlerMethods());
}
protected void detectHandlerMethods(final Object handler) {
// 如果 handler为String,则根据beanName获取handlerType否则获取类型
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
// 判断如果是cglib代理就返回原始的handler类型
final Class<?> userType = ClassUtils.getUserClass(handlerType);
// 返回处理后的requestMappingInfo
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
// 注解handlerMethod到mappingRegistry
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
中间的处理标签的过程比较复杂~感兴趣可以看看,
最后注册就是将各种信息保存到mappingRegistry里面:
下篇就讲请求流程,这时候mapping就至关重要了~
HandlerAdapter
适配器在请求的时候,会根据对应的handler获取对应的handler适配器,
由于是遍历handlerAdapter的集合,来查找这个handlerAdapter是否匹配这个Handler,调用的都是HandlerAdapter中的supports方法。
HandlerAdapter的主要几个实现HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter(最重要),:
SimpleControllerHandlerAdapter
我们看supports方法,就是判断是否是Controller类,对应的控制器实现了Controller类接口就使用这个适配器,然后执行也是执行handler方法,SimpleControllerHandlerAdapter,HttpRequestHandlerAdapter都是直接执行对应handler的handleRequest方法就返回了,比较简单:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
HttpRequestHandlerAdapter同理实现HttpRequestHandler接口的
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof HttpRequestHandler);
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
RequestMappingHandlerAdapter(重要)
这个类没有判断,是根据父类去判断的,父类判断是否是HandlerMethod类,然后执行子类的supportsInternal,这个方法直接返回true,可以自己去实现AbstractHandlerMethodAdapter然后自己定义规则适配,
我们看这个类的初始化方法,实现了InitializingBean,就看afterPropertiesSet方法:
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
//初始化ControllerAdvice注解需要的东西
initControllerAdviceCache();
//获取参数解析器
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//获取桥接方法的参数
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//返回参数参数解析
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
初始化了一些组件,像参数解析器,返回参数解析器等等,在对请求进行解析的时候至关重要.