SpringFramework之@Controller/@RequestMapping解析

    分析版本Spring5.0.9.release,Springboot2.0.3.release

    spring-webmvc的META-INFO/spring.handles文件中,有MvcNamespaceHandler,这是用来解析标签的,来看下MvcNamespaceHandler的init(),如下List-1,我们暂时只关注AnnotationDrivenBeanDefinitionParser。

    List-1

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

    AnnotationDrivenBeanDefinitionParser的parse方法里面有很多代码,但是我们只关注俩个,如下List-2:

  1. 用RootBeanDefinition将RequestMappingHandlerMapping注册到spring容器中。
  2. MvcNamespaceUtils.registerDefaultComponents中,将BeanNameUrlHandlerMapping注册到spring容器中、将HttpRequestHandlerAdapter注册到spring容器中、将SimpleControllerHandlerAdapter注册到spring容器中、将HandlerMappingIntrospector注册到容器中。

    List-2

@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext context) {
    ...
    RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
    ...
    // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
    MvcNamespaceUtils.registerDefaultComponents(context, source);
    return null;
}

    RequestMappingHandlerMapping的继承图如下图1所示:

                                                                          图1

    图1中,AbstractHandlerMethodMapping实现了接口InitializingBean,实现了afterPropertiesSet(),如果了解SpringIOC,应该知道这个方法意味着什么,Spring在创建Bean的时候会调用这个方法。

    List-3

@Override
public void afterPropertiesSet() {
	initHandlerMethods();
}

    由List-3知道afterPropertiesSet调用了initHandlerMethods(),如下List-4,首先从ApplicationContext或者所有的beanName,之后循环它们。isHandler方法由子类RequestMappingHandlerMapping实现,判断类上是否有Controller或者RequestMapping注解,所以即使不加上@Controller,只是用@RequestMapping注解也可以。List-4中的handlerMethodsInitialized是空方法,不用管。

    List-4

protected void initHandlerMethods() {
	if (logger.isDebugEnabled()) {
		logger.debug("Looking for request mappings in application context: " + getApplicationContext());
	}
	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 {
				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);
				}
			}
			if (beanType != null && isHandler(beanType)) {
				detectHandlerMethods(beanName);
			}
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

    来看List-4中的方法detectHandlerMethods,传入的是String类型的bean name,如下List-5,首先获取bean name对应的Class,getMappingForMethod在RequestMappingHandlerMapping中实现,如List-6所示,判断方法上是否有RequestMapping注解,如果有,则获取参数、path、header等信息,用builder模式构造出RequestMappingInfo。MethodIntrospector.selectMethods会遍历类上的方法,所以整体上对类的所有方法进行是否有RequestMapping的检查。需要注意的是,类似GetMapping等是组合注解,它们还是基于RequestMapping,所以方法上有GetMapping/PostMapping等都会会扫描并创建出对应的RequestMappingInfo。

    List-5

protected void detectHandlerMethods(Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		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);
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

    List-6

@Override
@Nullable
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;
}

@Nullable
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);
}

protected RequestMappingInfo createRequestMappingInfo(
		RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

	RequestMappingInfo.Builder builder = RequestMappingInfo
			.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();
}

    List-5中的registerHandlerMethod,会将得到的Mapper信息注册到mappingRegistry到,这个mappingRegistry后面在DispatcherServlet中使用到。注意传入到registerHandlerMethod方法的handler是String类型的bean name。

    Springboot中,RequestMappingHandlerMapping是通过@Configuration方式注入的,如下List-7

    List-7

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
	RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
...

Reference

  1. 源码
  2. https://www.cnblogs.com/lucas2/p/9419147.html

转载于:https://my.oschina.net/u/2518341/blog/3065849

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值