SpringMvc源码分析--配置文件解析

        我们简单分析一下springmvc配置解析过程,我个人认为理解这个过程对于后续学习是有帮助的,毕竟配置文件是入口。

一、认识springmvc.xml配置文件

        下面这个是springmvc中的配置,与spring的配置类似,只不过里面增加了springmvc特有的配置项,假设以default-servelt-handler举例说明。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context
                            https://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/mvc
                            https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.example.controller"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <mvc:default-servlet-handler/>
 ...
</beans>

二、入口

2.1、如何找到入口呢?

这里有简单说一下我的学习方式,具体有两种方式:

1)我们打开spring代码目录,可以通过代码目录进行猜测,因为spring的代码结构比较清晰,所以这种方式是最快的,虽然不能一次性找对,但多点几个文件也是可以找到的

2)搜索+断点调试

        这种方法如果如果匹配串准确度比较高,应该也能很快找到对应的文件,举个反例比如:搜bean可能会搜出很多文件,这样的字段就不是适合搜索。当我们找到怀疑的文件,就可以直接通过断点调试方式,来确定是不是最终能进到方法中。

2.2、注册解析器

springmvc配置文件中能用到的所有标签都在下面定义中

/**
 * {@link NamespaceHandler} for Spring MVC configuration namespace.
 *
 * @author Keith Donald
 * @author Jeremy Grelle
 * @author Sebastien Deleuze
 * @since 3.0
 * 用于解析springmvc配置文件中的配置项
 */
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());
	}

}

三、default-servlet-handler解析器

        default-servlet-handler解析器代码比较少,结构清晰,在实际开发中肯定会用的,所以用这个进行分析。

class DefaultServletHandlerBeanDefinitionParser implements BeanDefinitionParser {
	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		Object source = parserContext.extractSource(element);

		String defaultServletName = element.getAttribute("default-servlet-name"); //获取属性的值
		//创建BeanDefinition
		RootBeanDefinition defaultServletHandlerDef = new RootBeanDefinition(DefaultServletHttpRequestHandler.class);
		defaultServletHandlerDef.setSource(source);
		defaultServletHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		if (StringUtils.hasText(defaultServletName)) {
			defaultServletHandlerDef.getPropertyValues().add("defaultServletName", defaultServletName);
		}
		//注册到BeanDefinitionRegistry
		String defaultServletHandlerName = parserContext.getReaderContext().generateBeanName(defaultServletHandlerDef);
		parserContext.getRegistry().registerBeanDefinition(defaultServletHandlerName, defaultServletHandlerDef);
		parserContext.registerComponent(new BeanComponentDefinition(defaultServletHandlerDef, defaultServletHandlerName));

        //这里很关键,将处理器映射器和Servlet进行关联
		Map<String, String> urlMap = new ManagedMap<>();
		urlMap.put("/**", defaultServletHandlerName); //处理所有请求

		//创建BeanDefinition,这个SimplerUrlHandlerMapping也是一个处理器映射器
		RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
		handlerMappingDef.setSource(source);
		handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
		//注册到BeanDefinitionRegistry
		String handlerMappingBeanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef);
		parserContext.getRegistry().registerBeanDefinition(handlerMappingBeanName, handlerMappingDef);
		parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, handlerMappingBeanName));

		// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
        //注册各种组件 比如说适配器,拦截器
		MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

		return null;
	}
}
	public static void registerDefaultComponents(ParserContext context, @Nullable Object source) {
		registerBeanNameUrlHandlerMapping(context, source);
		registerHttpRequestHandlerAdapter(context, source);//适配器
		registerSimpleControllerHandlerAdapter(context, source);//适配器
		registerHandlerMappingIntrospector(context, source);//拦截器
		registerLocaleResolver(context, source);
		registerThemeResolver(context, source);
		registerViewNameTranslator(context, source);
		registerFlashMapManager(context, source);
	}

四、总结

        本篇并没有分析太多的源码,介绍了一种看源码的方式,希望能帮助大家

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值