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关系图
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的属性中。












网友评论