How Spring @RequestMapping processing (how to map the request path controller class or method)

Address reprint: http://blog.csdn.net/j080624/article/details/56278461
order to reduce the length of the article, the article makes more goal oriented, simple technology, we will not cite a variety of content such as the @RequestMapping usage.
Specific click to view @RequestMapping usage
article is specific to the following questions:

How Spring @RequestMapping processing (how to map the request path controller class or method)

Spring how to dispatches the request to the correct controller class or method

Spring realize how flexible controller method

在Spring MVC 3.1 之前的版本中,Spring默认使用 DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter来处理 @RequestMapping注解和请求方法调用,而从3.1开始提供了一组新的API完成这些工作。相比之下,新的API更加的合理完善,开放,易拓 展,面向对象。这篇文章便是基于3.1的新API进行剖析的。

First, the concept resolve
before we begin to understand the new interfaces introduced new API, or classes, which will help to understand the process behind. Have to say that the new API provides more beautiful abstraction, object-oriented you can feel the charm.

RequestMappingInfo This class is an abstract map request, which contains the request path, a request method, request class information. In fact, it can be seen as a @RequestMapping of the corresponding class.

This type of packaging HandlerMethod processor instance (Controller Bean) and a processing method of Example (Method), and a method parameter array (MethodParameter [])

MethodParameter class 2.0 from there, that encapsulates the information and a parameter of behavioral methods, such as the index of the parameter, the parameter relevant to the method of Example instance or configuration, the type of parameter.

HandlerMapping class that implements the interface is used to define mapping between the previous request and a processor, which only defines a method getHandler.

AbstractHandlerMethodMapping HandlerMapping This is basically a class that defines the mapping between request HandlerMethod instance.

RequestMappingInfoHandlerMapping this is AbstractHandlerMethodMapping implementation class, he maintains a RequestMappingInfo and HandlerMethod the Map property.

This is RequestMappingInfoHandlerMapping RequestMappingHandlerMapping subclass, it @RequestMapping annotations into RequestMappingInfo example, and used as a parent class. This is what we deal with @RequestMapping end.

This interface defines InitializingBean Bean its implementation may perform custom initialization operation after completion of the container property, we would AbstractHandlerMethodMapping implement this interface, and defines a set of custom action, our process is used to detect @RequestMapping annotations.

概念讲的太多总不是什么好事。但明白了上述概念基本上就成功一半了,其中的实现相对@Autowired那篇简单多了。

Two, InitialiZingBean.afterPropertySet ()
We start from scratch, to see in the end is how to detect and deal with Spring we @RequestMapping annotations. I wonder if we still remember this code does not mind:

[Java] View Plain Copy
Object exposedObject = the bean;
the try {
populateBean (the beanName, MBD, instanceWrapper);
IF (exposedObject = null!) {
exposedObject = initializeBean (the beanName, exposedObject, MBD);
}
}
This is BeanFactory created Bean process a piece of code to be executed, wherein the method is populateBean @Autowired annotation processing procedure performed by the attribute automatic injector operation. Because initializeBean method at that time did not say nothing to do with the topic, but this time it is the focus of our attention.

上面概念中我们讲到InitiaizingBean接口,它的实现Bean会在容器完成属性注入后执行一个自定义操作,这不就满足initializeBean方法的执行唤醒嘛,我们来看它的实现:

[Java] Plain View Copy
protected Object initializeBean (Final String the beanName, the bean Final Object, RootBeanDefinition MBD) {
IF (of System.getSecurityManager ()! = null) {
an AccessController.doPrivileged (the PrivilegedAction new new () {
public Object RUN () {
invokeAwareMethods (beanName, bean);
return null;
}
}, getAccessControlContext ());
}
the else {// here to detect whether the current row Aware bean implement some interface and call the relevant method, we do not care.
invokeAwareMethods (the beanName, the bean);
}

    Object wrappedBean = bean;  
    if (mbd == null || !mbd.isSynthetic()) {//BeanPostProcessor 的回调,不关心  
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);  
    }  

    try {  
        invokeInitMethods(beanName, wrappedBean, mbd);//这是我们需要关心的,下面看下它的实现  
    }  

    if (mbd == null || !mbd.isSynthetic()) {//BeanPostProcessor 的回调,不关心  
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);  
    }  
    return wrappedBean;  
}  

We then look at the realization invokeInitMethods method:

[java] view plain copy
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
//是否是InitializingBean的实例
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean &&
(mbd == null || !mbd.isExternallyManagedInitMethod(“afterPropertiesSet”))) {
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {//利用系统安全管理器调用
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
}
else {// call InitializingBean of afterPropertiesSet method.
((The InitializingBean) the bean) .afterPropertiesSet ();
}
}
// custom calling initialization methods. . . Omission, does not care
}
on an article about mvc: annotation-driven / article, we said, when coupled with the flag in the configuration file, Spring (3.1) will default to our registered RequestMappingHandlerMapping etc. Bean definition. And RequestMappingHandlerMapping achieved InitializingBean interface, so that during initialization and fitting Bean instance, to execute the above-described code, he will perform afterPropertySet method. We then look at his afterPropertySet method:

[java] view plain copy
public void afterPropertiesSet() {
initHandlerMethods();
}

//Scan beans in the ApplicationContext, detect and register handler methods.  
protected void initHandlerMethods() {  
    //扫描所有注册的Bean  
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?  
       BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(),   
            Object.class) : getApplicationContext().getBeanNamesForType(Object.class));  
    //遍历这些Bean,依次判断是否是处理器,并检测其HandlerMethod  
    for (String beanName : beanNames) {  
        if (isHandler(getApplicationContext().getType(beanName))){  
            detectHandlerMethods(beanName);  
        }  
    }  
    //这个方法是个空实现,不管他  
    handlerMethodsInitialized(getHandlerMethods());  
}  

It is called directly initHandlerMethods () method, and the method is described as: the scanning ApplicationContext Beans, and the registration processor detecting method. we are close.

Third, the detection @RequestMapping
we look at it is how to determine whether the processor, as well as how detect Handler Methods of:

[Java] Plain View Copy
@Override
protected Boolean isHandler (Class <?> BeanType) {
return ((AnnotationUtils.findAnnotation (BeanType, Controller.class)! = null) ||
(AnnotationUtils.findAnnotation (BeanType, RequestMapping.class)! null =));
}
aha, it is very simple to see if there is a comment tag @Controller or @RequestMapping

[java] view plain copy
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String) ?
getApplicationContext().getType((String) handler) : handler.getClass();
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Set methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter(){
public boolean matches(Method method) {//只选择被@RequestMapping标记的方法
return getMappingForMethod(method, userType) != null;
}
});

    for (Method method : methods) {  
        //根据方法上的@RequestMapping来创建RequestMappingInfo实例。  
        T mapping = getMappingForMethod(method, userType);  
        //注册请求映射  
        registerHandlerMethod(handler, method, mapping);  
    }  
}  

The whole detection process is substantially clear: 1) through all of the methods Handler, to find a method in which a labeled @RequestMapping annotations. 2) then traverse these methods, generating RequestMappingInfo instance. 3) The method RequestMappingInfo examples and registered to the cache processor.

下面我们看看细节:

[Java] Plain View Copy
@Override
protected RequestMappingInfo getMappingForMethod (<?> Method, Method, Class handlerType) {
RequestMappingInfo info = null;
// Get the method of Example @RequestMapping method.
MethodAnnotation = @RequestMapping
AnnotationUtils.findAnnotation (Method,, RequestMapping.class);
IF (! MethodAnnotation = null) {// method is annotated
RequestCondition methodCondition = getCustomMethodCondition (method) < ?>; // always returns null
info = createRequestMappingInfo (methodAnnotation, methodCondition); // create MappingInfo
// checking for class belongs there @RequestMapping comment
@RequestMapping typeAnnotation = AnnotationUtils.findAnnotation (handlerType,
RequestMapping.class);
! IF (typeAnnotation = null) {// @RequestMapping notes have class hierarchy
<?> RequestCondition typeCondition = getCustomTypeCondition (handlerType); // null
// will RequestMapping and method-level class hierarchy RequestMapping combined with
info = createRequestMappingInfo (typeAnnotation, typeCondition) .combine (info);
}
}
return info;
}
very clear it , @RequestMapping first obtain information on the method and then get @RequestMapping information on the class level, and then the combination of the two, here we have what is necessary to re-create RequestMappingInfo objects under the understanding (including his internal structure), and how the class the level at the request mapping information and method-level combination?

[java] view plain copy
private RequestMappingInfo createRequestMappingInfo(RequestMapping annotation,
RequestCondition<?> customCondition) {
return new RequestMappingInfo(
new PatternsRequestCondition(annotation.value(), getUrlPathHelper(), getPathMatcher(),
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions),
new RequestMethodsRequestCondition(annotation.method()),
new ParamsRequestCondition(annotation.params()),
new HeadersRequestCondition(annotation.headers()),
new ConsumesRequestCondition(annotation.consumes(), annotation.headers()),
new ProducesRequestCondition(annotation.produces(), annotation.headers(),
getContentNegotiationManager()),
customCondition
);
}
Involving several classes, we generally understand the meaning:

PatternRequestCondition it is actually a URL pattern of the package, which contains a URL pattern Set collection. In fact, the value @RequestMapping notes worth package.

It is packaged RequestMethodRequestCondition annotation method attribute @RequestMapping

It is packaged ParamsRequestCondition @RequestMapping property annotation params

等等,依次类推。因此RequestMappingInfo其实就是对@RquestMapping 的封装。

下面我们再看看怎样进行Combine的:

[java] view plain copy
public RequestMappingInfo combine(RequestMappingInfo other) {
PatternsRequestCondition patterns = this.patternsCondition.combine(other.patternsCondition);
RequestMethodsRequestCondition methods = this.methodsCondition.combine(other.methodsCondition);
ParamsRequestCondition params = this.paramsCondition.combine(other.paramsCondition);
HeadersRequestCondition headers = this.headersCondition.combine(other.headersCondition);
ConsumesRequestCondition consumes = this.consumesCondition.combine(other.consumesCondition);
ProducesRequestCondition produces = this.producesCondition.combine(other.producesCondition);
RequestConditionHolder custom = this.customConditionHolder.combine(other.customConditionHolder);

return new RequestMappingInfo(patterns, methods, params, headers, consumes,   
                produces, custom.getCondition());  

} Is very clear, for each element were combine operations, we look at here is how PatternRequestCondition combination, is to look at how to merge the url. The other is not much need.

[java] view plain copy
public PatternsRequestCondition combine(PatternsRequestCondition other) {
Set result = new LinkedHashSet();
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
for (String pattern1 : this.patterns) {
for (String pattern2 : other.patterns) {
result.add(this.pathMatcher.combine(pattern1, pattern2));
}
}
}
else if (!this.patterns.isEmpty()) {
result.addAll(this.patterns);
}
else if (!other.patterns.isEmpty()) {
result.addAll(other.patterns);
}
else {
result.add("");
}
return new PatternsRequestCondition(result, this.urlPathHelper, this.pathMatcher,
this.useSuffixPatternMatch, this.useTrailingSlashMatch, this.fileExtensions);
}
. 1) there are two pattern is to call PathMatcher combine method of merging two pattern.

2)只有一个有时,使用这个。

3)两个都没有时,为空“”。

现在真正的url拼接是由PathMatcher来完成的了。我们就不看他的代码了就是一串if else的组合,重点是考虑进各种情况,我们来看下方法的注释吧:



清晰,全面吧,有兴趣的可以看一下代码,这里不讲了。

Fourth, the registration request maps
that we have talked about above @RequestMapping detection and treatment, and generates a RequestMappingInfo example according to @RequestMapping, that Spring will certainly need to save this information together, to deal with our request.

第三节中我们提到一个方法还没有分析,就是registerHandlerMethod 方法:

[Java] View Plain Copy
protected void registerHandlerMethod (Object Handler, Method, Method, T Mapping) {
HandlerMethod HandlerMethod;
IF (Handler the instanceof String) {
String the beanName = (String) Handler;
HandlerMethod = new new HandlerMethod (the beanName, getApplicationContext (), Method );
}
the else {
HandlerMethod = new new HandlerMethod (Handler, method);
}
// the above lines is to generate a new instance of the new processor HandlerMethod instance, example methods, RequestMappingInfo
// below are viewed from the cache if there is present the HandlerMethod example, if there are not equal and thrown
HandlerMethod oldHandlerMethod = handlerMethods.get (Mapping);
IF (oldHandlerMethod = null && oldHandlerMethod.equals (HandlerMethod)!!) {
the throw new new IllegalStateException ();
}
// handlerMethods Map is a bond is RequestMappingInfo objects, instance values are HandlerMethod
// thus possible to process a plurality of mapping HandlerMethod example, but only by a mapping example of a processing method
this.handlerMethods.put (mapping, HandlerMethod);
// here to get all url mapping instance.
Patterns getMappingPathPatterns = SET (mapping);
for (String pattern: Patterns) {
IF (!. GetPathMatcher () isPattern (pattern)) {
// URLMap also the Map, is the key url mode, the value is RequestMappingInfo instance
// is therefore an example of mapping It may correspond to a plurality of pattern, but only a pattern corresponding to a mapping example
this.urlMap.add (pattern, mapping);
}
}
}

There may be a little bit around, in fact it is very simple, when a request arrives, to the need to find the matching urlMap url, mapping and obtain a corresponding instance, and then to match the acquired handlerMethods HandlerMethod instance.

Fifth, the connecting link between the
length of some long, exceeding the word limit, and only two into the ...

这章只分析了我们前面三个问题中的第一个,但是已经相当接近了。下一篇我们来讲,Spring怎样处理客户发来的请求,以及方法调用的。

Category: JAVA

Published 37 original articles · won praise 8 · views 5295

Guess you like

Origin blog.csdn.net/weixin_42714605/article/details/99620553