我们简单分析一下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);
}
四、总结
本篇并没有分析太多的源码,介绍了一种看源码的方式,希望能帮助大家
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)