Spring源码分析.docx
- 文档编号:15468089
- 上传时间:2023-07-04
- 格式:DOCX
- 页数:32
- 大小:28.67KB
Spring源码分析.docx
《Spring源码分析.docx》由会员分享,可在线阅读,更多相关《Spring源码分析.docx(32页珍藏版)》请在冰点文库上搜索。
Spring源码分析
软件体系结构
大作业报告
姓名:
王超
学号:
110511609
班级:
软工一班
院系:
数学与计算机
日期:
2014/6/2
任课教师:
丁月华
一实验目的
1.掌握需求分析的流程、方法以及技巧;
2.了解软件体系结构的基本概念,初步掌握中大型软件系统构架的分析与设计方法;
3.了解构建系统的目的是为了满足组织的需求,认识软件行业和开发组织在系统设计及其最终成败所起的作用,提高软件设计的基本素养;
4.了解常用软件设计模式的使用场景,解决方案;
5.认识系统的性能、可用性、安全性等质量属性都是受软件构架制约的,或者说这些属性的实现影响着设计师的设计选择;
二实验内容
本次源码分析是对于Spring的MFC和AOP进行代码分析。
下面对SpringMVC框架代码进行分析,这里着重分析SpringWebMVC框架的实现.从分析DispatcherServlet入手:
Java代码
//这里是对DispatcherServlet的初始化方法,根据名字我们很方面的看到对各个SpringMVC主要元素的初始化
protectedvoidinitFrameworkServlet()throwsServletException,BeansException{
initMultipartResolver();
initLocaleResolver();
initThemeResolver();
initHandlerMappings();
initHandlerAdapters();
initHandlerExceptionResolvers();
initRequestToViewNameTranslator();
initViewResolvers();
}
看到注解我们知道,这是DispatcherSerlvet的初始化过程,它是在WebApplicationContext已经存在的情况下进行的,也就意味着在初始化它的时候,IOC容器应该已经工作了,这也是我们在web.xml中配置Spring的时候,需要把DispatcherServlet的load-on-startup的属性配置为2的原因。
对于具体的初始化过程,很容易理解,我们拿initHandlerMappings()来看看:
Java代码
privatevoidinitHandlerMappings()throwsBeansException{
if(this.detectAllHandlerMappings){
//这里找到所有在上下文中定义的HandlerMapping,同时把他们排序
//因为在同一个上下文中可以有不止一个handlerMapping,所以我们把他们都载入到一个链里进行维护和管理
MapmatchingBeans=BeanFactoryUtils.beansOfTypeIncludingAncestors(
getWebApplicationContext(),HandlerMapping.class,true,false);
if(!
matchingBeans.isEmpty()){
this.handlerMappings=newArrayList(matchingBeans.values());
//这里通过order属性来对handlerMapping来在list中排序
Collections.sort(this.handlerMappings,newOrderComparator());
}
}
else{
try{
Objecthm=getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME,HandlerMapping.class);
this.handlerMappings=Collections.singletonList(hm);
}
catch(NoSuchBeanDefinitionExceptionex){
//Ignore,we'lladdadefaultHandlerMappinglater.
}
}
//如果在上下文中没有定义的话,那么我们使用默认的BeanNameUrlHandlerMapping
if(this.handlerMappings==null){
this.handlerMappings=getDefaultStrategies(HandlerMapping.class);
........
}
}
怎样获得上下文环境,可以参见我们前面的对IOC容器在web环境中加载的分析。
DispatcherServlet把定义了的所有HandlerMapping都加载了放在一个List里待以后进行使用,这个链的每一个元素都是一个handlerMapping的配置,而一般每一个handlerMapping可以持有一系列从URL请求到SpringController的映射,比如SimpleUrl
HandlerMaaping中就定义了一个map来持有这一系列的映射关系。
DisptcherServlet通过HandlerMapping使得Web应用程序确定一个执行路径,就像我们在HanderMapping中看到的那样,HandlerMapping只是一个借口:
Java代码
publicinterfaceHandlerMapping{
publicstaticfinalStringPATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE=
Conventions.getQualifiedAttributeName(HandlerMapping.class,"pathWithinHandlerMapping");
//实际上维护一个HandlerExecutionChain,这是典型的Command的模式的使用,这个执行链里面维护handler和拦截器
HandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException;
}
他的具体实现只需要实现一个接口方法,而这个接口方法返回的是一个HandlerExecutionChain,实际上就是一个执行链,就像在Command模式描述的那样,这个类很简单,就是一个持有一个Interceptor链和一个Controller:
Java代码
publicclassHandlerExecutionChain{
privateObjecthandler;
privateHandlerInterceptor[]interceptors;
........
}
而这些Handler和Interceptor需要我们定义HandlerMapping的时候配置好,比如对具体的SimpleURLHandlerMapping,他要做的就是根据URL映射的方式注册Handler和Interceptor,自己维护一个放映映射的handlerMap,当需要匹配Http请求的时候需要使用这个表里的信息来得到执行链。
这个注册的过程在IOC容器初始化SimpleUrlHandlerMapping的时候就被完成了,这样以后的解析才可以用到map里的映射信息,这里的信息和bean文件的信息是等价的,下面是具体的注册过程:
Java代码
protectedvoidregisterHandlers(MapurlMap)throwsBeansException{
if(urlMap.isEmpty()){
logger.warn("Neither'urlMap'nor'mappings'setonSimpleUrlHandlerMapping");
}
else{
//这里迭代在SimpleUrlHandlerMapping中定义的所有映射元素
Iteratorit=urlMap.keySet().iterator();
while(it.hasNext()){
//这里取得配置的url
Stringurl=(String)it.next();
//这里根据url在bean定义中取得对应的handler
Objecthandler=urlMap.get(url);
//Prependwithslashifnotalreadypresent.
if(!
url.startsWith("/")){
url="/"+url;
}
//这里调用AbstractHandlerMapping中的注册过程
registerHandler(url,handler);
}
}
}
在AbstractMappingHandler中的注册代码:
Java代码
protectedvoidregisterHandler(StringurlPath,Objecthandler)throwsBeansException,IllegalStateException{
//试图从handlerMap中取handler,看看是否已经存在同样的Url映射关系
ObjectmappedHandler=this.handlerMap.get(urlPath);
if(mappedHandler!
=null){
........
}
//如果是直接用bean名做映射那就直接从容器中取handler
if(!
this.lazyInitHandlers&&handlerinstanceofString){
StringhandlerName=(String)handler;
if(getApplicationContext().isSingleton(handlerName)){
handler=getApplicationContext().getBean(handlerName);
}
}
//或者使用默认的handler.
if(urlPath.equals("/*")){
setDefaultHandler(handler);
}
else{
//把url和handler的对应关系放到handlerMap中去
this.handlerMap.put(urlPath,handler);
........
}
}
handlerMap是持有的一个HashMap,里面就保存了具体的映射信息:
Java代码
privatefinalMaphandlerMap=newHashMap();
而SimpleUrlHandlerMapping对接口HandlerMapping的实现是这样的,这个getHandler根据在初始化的时候就得到的映射表来生成DispatcherServlet需要的执行链
Java代码
publicfinalHandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException{
//这里根据request中的参数得到其对应的handler,具体处理在AbstractUrlHandlerMapping中
Objecthandler=getHandlerInternal(request);
//如果找不到对应的,就使用缺省的handler
if(handler==null){
handler=this.defaultHandler;
}
//如果缺省的也没有,那就没办法了
if(handler==null){
returnnull;
}
//如果handler不是一个具体的handler,那我们还要到上下文中取
if(handlerinstanceofString){
StringhandlerName=(String)handler;
handler=getApplicationContext().getBean(handlerName);
}
//生成一个HandlerExecutionChain,其中放了我们匹配上的handler和定义好的拦截器,就像我们在HandlerExecutionChain中看到的那样,它持有一个handler和一个拦截器组。
returnnewHandlerExecutionChain(handler,this.adaptedInterceptors);
}
我们看看具体的handler查找过程:
Java代码
protectedObjectgetHandlerInternal(HttpServletRequestrequest)throwsException{
//这里的HTTPRequest传进来的参数进行分析,得到具体的路径信息。
StringlookupPath=this.urlPathHelper.getLookupPathForRequest(request);
.......//下面是根据请求信息的查找
returnlookupHandler(lookupPath,request);
}
protectedObjectlookupHandler(StringurlPath,HttpServletRequestrequest){
//如果能够直接能在SimpleUrlHandlerMapping的映射表中找到,那最好。
Objecthandler=this.handlerMap.get(urlPath);
if(handler==null){
//这里使用模式来对map中的所有handler进行匹配,调用了Jre中的Matcher类来完成匹配处理。
StringbestPathMatch=null;
for(Iteratorit=this.handlerMap.keySet().iterator();it.hasNext();){
StringregisteredPath=(String)it.next();
if(this.pathMatcher.match(registeredPath,urlPath)&&
(bestPathMatch==null||bestPathMatch.length()<=registeredPath.length())){
//这里根据匹配路径找到最象的一个
handler=this.handlerMap.get(registeredPath);
bestPathMatch=registeredPath;
}
}
if(handler!
=null){
exposePathWithinMapping(this.pathMatcher.extractPathWithinPattern(bestPathMatch,urlPath),request);
}
}
else{
exposePathWithinMapping(urlPath,request);
}
//
returnhandler;
}
我们可以看到,总是在handlerMap这个HashMap中找,当然如果直接找到最好,如果找不到,就看看是不是能通过MatchPattern的模式找,我们一定还记得在配置HnaderMapping的时候是可以通过ANT语法进行配置的,其中的处理就在这里。
这样可以清楚地看到整个HandlerMapping的初始化过程-同时,我们也看到了一个具体的handler映射是怎样被存储和查找的-这里生成一个ExecutionChain来储存我们找到的handler和在定义bean的时候定义的Interceptors.
让我们回到DispatcherServlet,初始化完成以后,实际的对web请求是在doService()方法中处理的,我们知道DispatcherServlet只是一个普通的Servlet:
Java代码
protectedvoiddoService(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{
.......
//这里把属性信息进行保存
MapattributesSnapshot=null;
if(WebUtils.isIncludeRequest(request)){
logger.debug("Takingsnapshotofrequestattributesbeforeinclude");
attributesSnapshot=newHashMap();
EnumerationattrNames=request.getAttributeNames();
while(attrNames.hasMoreElements()){
StringattrName=(String)attrNames.nextElement();
if(this.cleanupAfterInclude||attrName.startsWith(DispatcherServlet.class.getName())){
attributesSnapshot.put(attrName,request.getAttribute(attrName));
}
}
}
//Makeframeworkobjectsavailabletohandlersandviewobjects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE,this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE,this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE,getThemeSource());
try{
//这里使实际的处理入口
doDispatch(request,response);
}
finally{
//Restoretheoriginalattributesnapshot,incaseofaninclude.
if(attributesSnapshot!
=null){
restoreAttributesAfterInclude(request,attributesSnapshot);
}
}
}
我们看到,对于请求的处理实际上是让doDispatch()来完成的-这个方法很长,但是过程很简单明了:
Java代码
protectedvoiddoDispatch(finalHttpServletRequestrequest,HttpServletResponseresponse)throwsException{
HttpServletRequestprocessedRequest=request;
//这是从handlerMapping中得到的执行链
HandlerExecutionChainmappedHandler=null;
intinterceptorIndex=-1;
........
try{
//我们熟悉的ModelAndView开始出现了。
ModelAndViewmv=null;
try{
processedRequest=checkMultipart(request);
//这是我们得到handler的过程
mappedHandler=getHandler(processedRequest,false);
if(mappedHandler==null||mappedHandler.getHandler()==null){
noHandlerFound(processedRequest,response);
return;
}
//这里取出执行链中的Interceptor进行前处理
if(mappedHandler.getInterceptors()!
=null){
for(inti=0;i HandlerInterceptorinterceptor=mappedHandler.getInterceptors()[i]; if(! interceptor.preHandle(processedRequest,response,mappedHandler.getHandler())){ triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,null); return; } interceptorIndex=i; } } //在执行handler之前,用HandlerAdapter先检查一下handler的合法性: 是不是按Spring的要求编写的。 HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler()); mv=ha.handle(processedRequest,response,mappedHandler.getHandler()); //这里取出执行链中的Interceptor进行后
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Spring 源码 分析