文章目录
  1. 1. Springmvc注解驱动
    1. 1.1. 注解驱动的解析
    2. 1.2. RequestMappingHandlerMapping
      1. 1.2.1. 继承结构
      2. 1.2.2. 初始化
        1. 1.2.2.1. 初始化接口
        2. 1.2.2.2. 具体实现接口
      3. 1.2.3. 总结

Springmvc注解驱动

注解驱动的解析

​ 通过查看 spring-webmvc-xxx.jar 下的spring.handlers文件可以发现 mvc前缀的标签都是由 MvcNamespaceHandler 来进行解析的。

spring.handlers

1
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MvcNamespaceHandler extends NamespaceHandlerSupport {

@Override
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());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}

通过查看其内部唯一的方法 init() 的实现可以确定 <mvc:annotation-driven /> 的解析工作是由 AnnotationDrivenBeanDefinitionParser 类全权负责的。其实现了BeanDefinitionParser接口

唯一的parse()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {

public static final String HANDLER_MAPPING_BEAN_NAME = RequestMappingHandlerMapping.class.getName();

public static final String HANDLER_ADAPTER_BEAN_NAME = RequestMappingHandlerAdapter.class.getName();

//....省略其他属性

public BeanDefinition parse(Element element, ParserContext parserContext) {

//.....省略代码

//此处注册组件
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME)); //注册RequestMappingHandlerMapping
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME)); //注册REquestMappingHandlerAdapter
parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
parserContext.registerComponent(new BeanComponentDefinition(exceptionResolver, methodExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));

// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

parserContext.popAndRegisterContainingComponent();

return null;
}

}

观察该类对所继承接口的实现可以发现:

​ 向SpringMVC容器中注册了 ContentNegotiationManagerFactoryBean
​ 向SpringMVC容器中注册了 RequestMappingHandlerMapping (间接实现了HandlerMapping接口), order为0
​ 向SpringMVC容器中注册了 RequestMappingHandlerAdapter (间接实现了HandlerAdapter接口,直接实现了 InitializingBean接口,关于这个接口的实现,参见本人的另外一篇博客)
​ 向SpringMVC容器中注册了 MappedInterceptor
​ 向SpringMVC容器中注册了 ExceptionHandlerExceptionResolver (间接实现了HandlerExceptionResolver接口), order为0
​ 向SpringMVC容器中注册了 ResponseStatusExceptionResolver (间接实现了HandlerExceptionResolver接口), order为1
​ 向SpringMVC容器中注册了 DefaultHandlerExceptionResolver (间接实现了HandlerExceptionResolver接口), order为2

RequestMappingHandlerMapping

继承结构

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping

​ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping

​ public abstract class AbstractHandlerMethodMapping\<T> extends AbstractHandlerMapping implements InitializingBean

初始化

初始化接口

​ 该类实现了InitializingBean接口,因此初始化bean时会调用afterPropertiesSet()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;

}

InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。

补充说明:

1、Spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中通过init-method指定,两种方式可以同时使用。

2、实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率要高一点,但是init-method方式消除了对spring的依赖。

3、如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

参考:https://www.cnblogs.com/weiqihome/p/8922937.html

具体实现接口

1)public abstract class AbstractHandlerMethodMapping该类实现了InitializingBean的afterPropertiesSet()方法

AbstractHandlerMethodMapping—>afterPropertiesSet()

1
2
3
4
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}

调用了initHandlerMethods();

2)AbstractHandlerMethodMapping–>initHandlerMethods();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//获取容器中的bean名
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));

//遍历
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
//根据bean名获取该bean的类型(Class)
beanType = obtainApplicationContext().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在AbstractHandlerMethodMapping<T>类中抽象方法;
//判断是否是一个Handler
if (beanType != null && isHandler(beanType)) {
//检测Handler中的方法
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}

3)String[] beanNames获取容器中的bean名称,然后对bean进行遍历

4)isHandler()方法

RequestMappingHandlerMapping类对父类AbstractHandlerMethodMapping\<T>类的实现

RequestMappingHandlerMapping——–>isHandler

1
2
3
4
5
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

分析:

​ 判断该Bean是否属于Handler

​ 判断依据:是否有Controller注解 ,或者是否有RequestMapping注解

返回一个boolean类型

5)如果是一个Handler,则执行 ————- detectHandlerMethods(beanName)

AbstractHandlerMethodMapping–>detectHandlerMethods(beanName)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Look for handler methods in a handler.
* @param handler the bean name of a handler or a handler instance
*/
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());

if (handlerType != null) {
final Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) 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();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
}

该方法检测Handler(一个Controller)中的方法并进行注册

该方法主要代码分析:(没有详细分析,下次分析)

​ 1)获取userType中的映射方法放入Map集合中

1
2
3
4
5
6
7
8
9
10
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});

​ getMappingForMethod(method, userType); //返回一个请求映射信息

​ 1)userType为我们自定义的, 被@Controller注解所修饰的类.
​ 2)method为 java.lang.reflect.Method 类型, 为我们所自定义的userType类型中的方法.
​ 3)该getMappingForMethod方法也是抽象的, 交由RequestMappingHandlerMapping类来实现.

1
2
3
4
5
6
7
8
9
10
11
12
13
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 抽取该方法上注解的@RequestMapping
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 抽取handlerType(即我们自定义的Controller类)上注解的@RequestMapping
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 合并两个RequestMapping的信息(controller路径+method)
info = typeInfo.combine(info);
}
}
return info;
}

createRequestMappingInfo()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

RequestMappingInfo.Builder builder = RequestMappingInfo
/* 这里说明我们是可以在配置@RequestMapping时, 使用spel表达式的; 例如@RequestMapping("/yuyue/${url.mh}/login") */
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build();
}

2)注册获取到的映射方法

1
2
3
4
5
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}

registerHandlerMethod(handler, invocableMethod, mapping);

​ 1)andler为传入的bean name
​ 2)method为 java.lang.reflect.Method 类型, 为我们所自定义的userType类型中的方法.
​ 3)mappings.get(method)为我们使用getMappingForMethod 构造的RequestMappingInfo 实例

AbstractHandlerMethodMapping——->registerHandlerMethod()

1
2
3
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}

AbstractHandlerMethodMapping———>register()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);

if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//mappin与hanlderMethod映射
this.mappingLookup.put(mapping, handlerMethod);

List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//url与mapping映射
this.urlLookup.add(url, mapping);
}

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();
}
}

//属性:private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();

this.mappingLookup.put(mapping, handlerMethod);

mapping:映射路径(例如:/login)

handlerMethod: 包含了bean和方法信息

​ 抽取出来RequestMappingInfo 信息 注册到 LinkedHashMap<RequestMappingInfo,HandlerMethod>类型的全局字段handlerMethods

//属性:private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();

this.urlLookup.add(url, mapping);

url:浏览器请求路径(例如:/login)

mapping:映射方法路径(“例如: /login”)

将映射关系注册到urlLookup全局变量中

总结

1)context:component-scan 默认是将所有@Component注解的类扫描进容器;

​ @Controller自身就是被@Component修饰的

2)mvc:annotation-driven的解析工作是由 AnnotationDrivenBeanDefinitionParser 类全权负责的。
3)AnnotationDrivenBeanDefinitionParser会向SpringMVC容器中注册了 RequestMappingHandlerMapping (间接实现了HandlerMapping接口), order为0
4)查看RequestMappingHandlerMapping 类的继承链就会发现, 其祖先类 AbstractHandlerMethodMapping 实现了 InitializingBean
5)而对InitializingBean的实现中, 会回调AbstractHandlerMethodMapping–>initHandlerMethods()的实现,其中的isHandler()方法中有对@Controller,@RequestMapping注解的扫描

参考:https://blog.csdn.net/lqzkcx3/article/details/78159708

文章目录
  1. 1. Springmvc注解驱动
    1. 1.1. 注解驱动的解析
    2. 1.2. RequestMappingHandlerMapping
      1. 1.2.1. 继承结构
      2. 1.2.2. 初始化
        1. 1.2.2.1. 初始化接口
        2. 1.2.2.2. 具体实现接口
      3. 1.2.3. 总结