SpringMVC4.x源码分析(三):解析Controllor和HandlerMethod

回顾本例springmvc-config.xml的配置:

<context:component-scan base-package="com.spring"/>
<mvc:annotation-driven />

component-scan:扫描指定包下被@Component,@Service@Controller@Repository,@Configuration注解所标注的class。实际上,都是通过@Component来完成的。

annotation-driven:注册SpringMVC的web组件,并完成HandlerMethod的解析。

名称空间处理器:NamespaceHandler

13be511264fecb9d36f3c07ef1d4d64a13a.jpg

context:component-scan标签由ContextNamespaceHandler处理器处理。

mvc:annotation-driven标签由MvcNamespaceHandler处理器处理。

ContextNamespaceHandler处理器源码:

public class ContextNamespaceHandler extends NamespaceHandlerSupport {

@Override
public void init() {
	registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
	registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
	registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
	registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
	registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
	registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
	registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
	registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

}

由此可见,component-scan是由具体的ComponentScanBeanDefinitionParser解析器解析,它实现了BeanDefinitionParser接口,完成扫描指定包路径下的class文件,并注册所有满足条件的BeanDefinition。

ComponentScanBeanDefinitionParser解析器

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
	String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
	basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
	String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

	ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    // 完成扫描并注册BeanDefinitions
	Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
	registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

	return null;
}

ClassPathScanningCandidateComponentProvider是ClassPathBeanDefinitionScanner父类,我们重点关注findCandidateComponents(String basePackage)方法。

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
	try {
        // 首先将我们配置的com.spring包修改为classpath*:com/spring/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                    // 重点关注该方法
					if (isCandidateComponent(metadataReader)) {
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							//...
							candidates.add(sbd);
						}
						//...
	return candidates;
}

isCandidateComponent(metadataReader)方法,完成了@Component的筛选工作。

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
	for (TypeFilter tf : this.excludeFilters) {
		if (tf.match(metadataReader, this.metadataReaderFactory)) {
			return false;
		}
	}
	for (TypeFilter tf : this.includeFilters) {
		if (tf.match(metadataReader, this.metadataReaderFactory)) {
			return isConditionMatch(metadataReader);
		}
	}
	return false;
}

includeFilters指定了筛选条件为:@Component注解的类。

faf16c80c6b2e8dd6038c2826676c4d7dcf.jpg

由于我们并没有在springmvc-config.xml中给component-scan配置includeFilters标签过滤属性,所以includeFilters取的是默认值@Component注解

protected void registerDefaultFilters() {
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	//...
}

既然默认读取@Component标注的类,那么,那些仅仅标注了@Service@Controller@Repository,@Configuration注解的类是怎么被包含进来的呢?原理在于,直接或间接使用@Component标注的类,都会被包含进来。@Service@Controller@Repository,@Configuration都是被@Component所标注的。

AnnotationTypeFilter.matchSelf()源码:

@Override
protected boolean matchSelf(MetadataReader metadataReader) {
	AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
	return metadata.hasAnnotation(this.annotationType.getName()) ||
			(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}

hasAnnotation:直接被@Component标注。

hasMetaAnnotation:间接被@Component标注,如@Service@Controller@Repository,@Configuration。

AnnotationDrivenBeanDefinitionParser解析器

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("velocity-configurer", new VelocityConfigurerBeanDefinitionParser());
	registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
	registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
	registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}

}

AnnotationDrivenBeanDefinitionParser.parse()方法很长:

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
	Object source = parserContext.extractSource(element);
	XmlReaderContext readerContext = parserContext.getReaderContext();

	CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
	parserContext.pushContainingComponent(compDefinition);

	RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);

	RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
	handlerMappingDef.setSource(source);
	handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	handlerMappingDef.getPropertyValues().add("order", 0);
	handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);

	if (element.hasAttribute("enable-matrix-variables")) {
		Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
		handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
	}
	else if (element.hasAttribute("enableMatrixVariables")) {
		Boolean enableMatrixVariables = Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
		handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
	}

	configurePathMatchingProperties(handlerMappingDef, element, parserContext);
	readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);

	RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
	handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);

	RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
	RuntimeBeanReference validator = getValidator(element, source, parserContext);
	RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

	RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
	bindingDef.setSource(source);
	bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	bindingDef.getPropertyValues().add("conversionService", conversionService);
	bindingDef.getPropertyValues().add("validator", validator);
	bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);

	ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
	ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext);
	ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
	String asyncTimeout = getAsyncTimeout(element);
	RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
	ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
	ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);

	RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
	handlerAdapterDef.setSource(source);
	handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
	handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
	handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
	addRequestBodyAdvice(handlerAdapterDef);
	addResponseBodyAdvice(handlerAdapterDef);

	if (element.hasAttribute("ignore-default-model-on-redirect")) {
		Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
		handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
	}
	else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
		// "ignoreDefaultModelOnRedirect" spelling is deprecated
		Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
		handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
	}

	if (argumentResolvers != null) {
		handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
	}
	if (returnValueHandlers != null) {
		handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
	}
	if (asyncTimeout != null) {
		handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
	}
	if (asyncExecutor != null) {
		handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
	}

	handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
	handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
	readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME , handlerAdapterDef);

	RootBeanDefinition uriContributorDef =
			new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
	uriContributorDef.setSource(source);
	uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
	uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
	String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
	readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);

	RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
	csInterceptorDef.setSource(source);
	csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
	RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
	mappedInterceptorDef.setSource(source);
	mappedInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
	mappedInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
	String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedInterceptorDef);

	RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
	methodExceptionResolver.setSource(source);
	methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
	methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
	methodExceptionResolver.getPropertyValues().add("order", 0);
	addResponseBodyAdvice(methodExceptionResolver);
	if (argumentResolvers != null) {
		methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
	}
	if (returnValueHandlers != null) {
		methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
	}
	String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);

	RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
	statusExceptionResolver.setSource(source);
	statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	statusExceptionResolver.getPropertyValues().add("order", 1);
	String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);

	RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
	defaultExceptionResolver.setSource(source);
	defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	defaultExceptionResolver.getPropertyValues().add("order", 2);
	String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);

	parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
	parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
	parserContext.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
	parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
	parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
	parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
	parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));

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

	parserContext.popAndRegisterContainingComponent();

	return null;
}

mvc:annotation-driven解析器,向Spring IOC容器注册了很多SpringMVC的web组件,我们重点关注下面几个组件,其余读者可自行了解:

1、RequestMappingHandlerMapping:负责解析HandlerMethod,并根据request请求返回HandlerExecutionChain,HandlerExecutionChain是HandlerMethod和方法拦截器的合体。

2、RequestMappingHandlerAdapter:负责处理request请求,并返回ModelAndView对象。

3、DefaultFormattingConversionService:类型转换服务类,如String to Date,Date to String。

4、HttpMessageConverter:消息转换器,如根据HTTP的MIME类型,JavaBean to Json,JavaBean to XML。

5、ConfigurableWebBindingInitializer:WebDataBinder的初始化器。

...

其余可自行查看。

RequestMappingHandlerMapping实现了InitializingBean接口,那么,在Spring IOC容器创建该bean对象时,会调用它的afterPropertiesSet()方法,完成HandlerMethod的解析工作。

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

protected void initHandlerMethods() {
	//...
    // 从IOC容器中获得所有的beans
	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) {
				//...
			}
            // isHandler()检测是否有@Controller注解
			if (beanType != null && isHandler(beanType)) {
                // 从Controllor中解析出被@RequestMapping标注的方法
				detectHandlerMethods(beanName);
			}
		}
	}
    // 空方法
	handlerMethodsInitialized(getHandlerMethods());
}
protected void detectHandlerMethods(final Object handler) {
	Class<?> handlerType = (handler instanceof String ?
			getApplicationContext().getType((String) handler) : handler.getClass());
	final Class<?> userType = ClassUtils.getUserClass(handlerType);
    // T为RequestMappingInfo对象
	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) {
						//...
					}
				}
			});

	//...
	}
	for (Map.Entry<Method, T> entry : methods.entrySet()) {
		Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
		T mapping = entry.getValue();
		registerHandlerMethod(handler, invocableMethod, mapping);
	}
}
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 方法上的@RequestMapping
	RequestMappingInfo info = createRequestMappingInfo(method);
	if (info != null) {
        // 类上的@RequestMapping
		RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
		if (typeInfo != null) {
            // 取二者的并集(合并)
			info = typeInfo.combine(info);
		}
	}
	return info;
}
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注解标注的方法或类。

下面我们看看RequestMappingInfo的类结构:

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {

private final PatternsRequestCondition patternsCondition;

private final RequestMethodsRequestCondition methodsCondition;

private final ParamsRequestCondition paramsCondition;

private final HeadersRequestCondition headersCondition;

private final ConsumesRequestCondition consumesCondition;

private final ProducesRequestCondition producesCondition;

private final RequestConditionHolder customConditionHolder;
}

我画一个图,大家就明白了。

2d305fba568a8b337ebb76d90c352025488.jpg

紧接着,将RequestMappingInfo封装成HandlerMethod,注册到MappingRegistry中。

AbstractHandlerMethodMapping.MappingRegistry.register():

public void register(T mapping, Object handler, Method method) {
	this.readWriteLock.writeLock().lock();
	try {
        // T mapping即RequestMappingInfo对象
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		assertUniqueMethodMapping(handlerMethod, mapping);

		//...
		this.mappingLookup.put(mapping, handlerMethod);
        // 不带通配符*和?号的,直接加入urlLookup
		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();
	}
}
class MappingRegistry {
//T为RequestMappingInfo对象
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();

private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();

private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();

private final Map<String, List<HandlerMethod>> nameLookup =
		new ConcurrentHashMap<String, List<HandlerMethod>>();

private final Map<HandlerMethod, CorsConfiguration> corsLookup =
		new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();
}

MappingRegistry是RequestMappingHandlerMapping的属性,MappingRegistry对RequestMappingInfo进行了多种缓存映射,方便查找。

至此,context:component-scan、mvc:annotation-driven、RequestMappingInfo以及HandlerMethod的解析及工作原理,都已经基本明确了。

context:component-scan:主要完成bean的解析工作。

mvc:annotation-driven:主要完成从controllor bean中解析出RequestMappingInfo,封装为HandlerMethod对象。

原文出处:http://my.oschina.net/zudajun

转载于:https://my.oschina.net/zudajun/blog/1827594

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值