您的位置:首页 > 移动开发

SpingMVC模块常用几种handlerMapping的初始化过程

2017-10-25 15:45 597 查看
以xml文件为例,内容如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 默认的注解映射的支持 -->
<context:component-scan base-package="**.**.controller"/>
<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="fastJsonHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<mvc:default-servlet-handler />
<!-- 处理JSON数据转换的 -->
<bean id="fastJsonHttpMessageConverter"
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 为了处理返回的JSON数据的编码,默认是ISO-88859-1的,这里把它设置为utf-8,解决有乱码的情况 -->
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</beans>


这里,主要关心的是HandlerMapping接口实现类的初始化问题,所以主要关注以下两个标签即可。

<mvc:annotation-driven>
<mvc:default-servlet-handler/>


针对mvc的命名空间,spring-webmvc工程中spring.handlers内容如下http://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler

public class MvcNamespaceHandler extends NamespaceHandlerSupport {

public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
}

}


1、RequestMappingHandlerMapping类的引入与初始化

RequestMappingHandlerMapping类引入

<mvc:annotation-driven>


annotation-driven标签,用来支持基于注解的映射,它的实现类是AnnotationDrivenBeanDefinitionParser,这个类又向容器中注册了RequestMappingHandlerMapping,它就是一个HandlerMapping接口实现类。 RequestMappingHandlerMapping是默认的第一个HandlerMapping,因为它实现了order接口,同时赋值为0。

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
。。。。。。
public BeanDefinition parse(Element element, ParserContext parserContext) {
。。。。。。
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//RequestMappingHandlerMapping是handler中默认的第一个,因为实现了order接口
handlerMappingDef.getPropertyValues().add("order", 0);
handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
。。。。。。
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

parserContext.popAndRegisterContainingComponent();

return null;
}

。。。。。。

}


RequestMappingHandlerMapping类初始化

这里主要是说url和handler之间映射关系的初始化,对应AbstractHandlerMethodMapping类的urlMap属性。RequestMappingHandlerMapping类实现了InitializingBean接口,所以初始化时会调用RequestMappingHandlerMapping类的afterPropertiesSet方法,url和handler之间映射关系的初始化就是这里,是通过扫描特定包内类的注解实现的。例如,扫描到com.winksi.roinchina.controller包下的RoinChinaController类时,发现getToken方法有注解@RequestMapping,所以就会向urlMap内,添加一条记录,key为/getToken。

/**
* Interface to be implemented by beans that need to react once all their
* properties have been set by a BeanFactory: for example, to perform custom
* initialization, or merely to check that all mandatory properties have been set.
*
* <p>An alternative to implementing InitializingBean is specifying a custom
* init-method, for example in an XML bean definition.
* For a list of all bean lifecycle methods, see the BeanFactory javadocs.
*
* @author Rod Johnson
* @see BeanNameAware
* @see BeanFactoryAware
* @see BeanFactory
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
* @see org.springframework.context.ApplicationContextAware
*/
public interface InitializingBean {

/**
* Invoked by a BeanFactory after it has set all bean properties supplied
* (and satisfied BeanFactoryAware and ApplicationContextAware).
* <p>This method allows the bean instance to perform initialization only
* possible when all bean properties have been set and to throw an
* exception in the event of misconfiguration.
* @throws Exception in the event of misconfiguration (such
* as failure to set an essential property) or if initialization fails.
*/
void afterPropertiesSet() throws Exception;

}


package com.winksi.roinchina.controller;
@Controller
public class RoinChinaController {

private static final Logger log = LoggerFactory.getLogger(RoinChinaController.class);

public RoinChinaController(){
log.info("RoinChinaController init");
}

/**
* 查询归属地v1.0接口
*
* @param input
* @return
*/
@RequestMapping(value = "/getToken", method = RequestMethod.POST)
@ResponseBody
public JSONObject getToken(@RequestBody JSONObject input) {
JSONObject json = new JSONObject();
json.put("akey", "avalue");
return json;
}
}




2、SimpleUrlHandlerMapping类的引入与初始化

SimpleUrlHandlerMapping类的引入

<mvc:default-servlet-handler/>


default-servlet-handler标签的解析,会引入DefaultServletHandlerBeanDefinitionParser解析类。在DefaultServletHandlerBeanDefinitionParser类的parse方法内,会引入SimpleUrlHandlerMapping类。

class DefaultServletHandlerBeanDefinitionParser implements BeanDefinitionParser {

public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);

String defaultServletName = element.getAttribute("default-servlet-name");
RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class);
defaultServletHandlerDef.setSource(source);
defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (StringUtils.hasText(defaultServletName)) {
defaultServletHandlerDef.getPropertyValues().add("defaultServletName", defaultServletName);
}
String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef);
parserContext.getRegistry().registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef);
parserContext.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName));

Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/**", defaultServletHandlerName);

RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);

String handlerMappingBeanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef);
parserContext.getRegistry().registerBeanDefinition(handlerMappingBeanName, handlerMappingDef);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, handlerMappingBeanName));

/**
* 里面有RootBeanDefinition beanNameMappingDef = new RootBeanDefinition(BeanNameUrlHandlerMapping.class);类的定义
*/
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

return null;
}

}


SimpleUrlHandlerMapping类的初始化

SimpleUrlHandlerMapping实现了ApplicationContextAware接口(定义setApplicationContext方法),所以初始化SimpleUrlHandlerMapping时,会调用SimpleUrlHandlerMapping类的setApplicationContext方法。因为SimpleUrlHandlerMapping没有实现setApplicationContext方法,所以实际调用的是ApplicationObjectSupport类的setApplicationContext方法。具体调用顺序,可以参考下图。



需要注意SimpleUrlHandlerMapping类的urlMap属性的赋值,这个属性的复制是在DefaultServletHandlerBeanDefinitionParser类注册SimpleUrlHandlerMapping类时实现的。具体代码如下

Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/**", defaultServletHandlerName);

RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
handlerMappingDef.setSource(source);
handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: