EnableWebMvc
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
EnableWebMvc
上使用@Import
导入了类DelegatingWebMvcConfiguration
,含义为在容器扫描bean时,会将导入的类一起处理。
导入的DelegatingWebMvcConfiguration
与父类WebMvcConfigurationSupport
DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
WebMvcConfigurationSupport
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = createRequestMappingHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors());
handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
handlerMapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
if (configurer.isUseSuffixPatternMatch() != null) {
handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch());
}
if (configurer.isUseRegisteredSuffixPatternMatch() != null) {
handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch());
}
if (configurer.isUseTrailingSlashMatch() != null) {
handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch());
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
handlerMapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
handlerMapping.setPathMatcher(pathMatcher);
}
return handlerMapping;
}
DelegatingWebMvcConfiguration
上的注解@Configuration
,说明其为完全配置类,从父类继承的requestMappingHandlerMapping
方法上的注解@Bean
,说明会将RequestMappingHandlerMapping
托管给容器,beanName为方法名。
RequestMappingHandlerMapping
的基类实现了InitializingBean
方法,在容器初始化该bean时,会执行其初始化方法afterPropertiesSet
,
RequestMappingHandlerMapping
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
super.afterPropertiesSet();
}
...
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
父类AbstractHandlerMethodMapping
的afterPropertiesSet
方法
AbstractHandlerMethodMapping
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
...
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
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);
}
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
从容器中获取了所有的Object
类型的bean,意味着拿到了所有bean,遍历bean使用isHandler
判断。拥有Controller
注解或者RequestMapping
注解的视为Handler
,对Handler
在detectHandlerMethods
方法内选出其内部可以处理请求的方法。
RequestMappingHandlerMapping
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
AbstractHandlerMethodMapping
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
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();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
MethodIntrospector
的selectMethods
方法
MethodIntrospector
public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
final Map<Method, T> methodMap = new LinkedHashMap<Method, T>();
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
Class<?> specificHandlerType = null;
if (!Proxy.isProxyClass(targetType)) {
handlerTypes.add(targetType);
specificHandlerType = targetType;
}
handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));
for (Class<?> currentHandlerType : handlerTypes) {
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
T result = metadataLookup.inspect(specificMethod);
if (result != null) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
methodMap.put(specificMethod, result);
}
}
}
}, ReflectionUtils.USER_DECLARED_METHODS);
}
return methodMap;
}
获取当前处理的bean和其接口类,对他们的所有方法,在inspect
中做处理,最终的处理在getMappingForMethod
方法中
RequestMappingHandlerMapping
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
}
return info;
}
可以看到传入的参数为当前正在处理的方法和类,先获取方法的RequestMappingInfo
,如果不为null再获取类的RequestMappingInfo
,然后将方法与类的RequestMappingInfo
相连接,构成最终的RequestMappingInfo
。(例如方法上的mapping为/method,类上的mapping为/controller,那么最终的请求路径为/controller/method)
RequestMappingHandlerMapping
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
RequestCondition<?> condition = (element instanceof Class ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
尝试从元数据中获取RequestMapping
注解,再判断当前处理的是method
还是class
,最终创建RequestMappingInfo
。
回到AbstractHandlerMethodMapping
的detectHandlerMethods
方法中,MethodIntrospector.selectMethods
方法执行完成之后的返回值是一个Map,包含所有能处理请求的方法。registerHandlerMethod
方法中对这些方法进行注册。
AbstractHandlerMethodMapping
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
内部类 MappingRegistry
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);
}
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
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<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
可以看到将内部类MappingRegistry
中,使用handler
与method
创建了HandlerMethod
,然后将其与RequestMappingInfo
按照KV的形式保存在MapmappingLookup
中。然后拿到mapping
内的路径,按照url
-mapping
的形式保存在MultiValueMap(一个Key对应多个Value)urlLookup
中。最后在Mapregistry
中保存了RequestMappingInfo
与MappingRegistration
的映射。
至此,RequestMappingHandlerMapping
的初始化方法执行完成。
总结:
- 声明注解
@EnableWebMvc
,会将注解上导入的类DelegatingWebMvcConfiguration
托管给容器 - 类
DelegatingWebMvcConfiguration
上声明了注解@Configuration
表示其是一个完全配置类,拥有配置Bean的能力。 - 它的父类
WebMvcConfigurationSupport
中使用@Bean
标注了方法requestMappingHandlerMapping
,表示想要将该方法的返回值托管给容器,最终将类RequestMappingHandlerMapping
托管给容器。 - 在容器初始化类
RequestMappingHandlerMapping
时,由于它的基类实现了接口InitializingBean
,所以它的初始化方法afterPropertiesSet
会被调用。 - 最终在基类
AbstractHandlerMethodMapping
的afterPropertiesSet
方法中调用了initHandlerMethods
方法。完成了对所有包含@Controller
注解或者@RequestMapping
注解的类的处理,将这些类中的带有@RequestMapping
注解的方法与其类合并为完全的RequestMappingInfo
,保存在AbstractHandlerMethodMapping
的属性中。
网友评论