ssh框架的构成分析和代码构架小结

时间:2019-05-13 17:18:51下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《ssh框架的构成分析和代码构架小结》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《ssh框架的构成分析和代码构架小结》。

第一篇:ssh框架的构成分析和代码构架小结

ssh框架的构成分析和代码构架小结

最近在弄j2ee,发现还是学到了很多东西,心情happy啊!昨天看到了一个文章是关于ssh的,就弄下来了,后面加点自己的东西,很感谢网上的各位前辈的总结。一个spring2.5+hibernate3.2+struts2.0组合框架,使用spring的IoC来管理应用的所有bean,包括struts2的action,充分发挥了spring轻量级框架的优势。

摘 要:针对当前Web应用程序开发面临的问题,结合目前比较流行的开源框架Spring、Struts和Hibernate,提出了一种开发J2EE Web应用的轻量级解决方案,以帮助开发人员在短期内搭建结构清晰、可复用性好、维护方便的Web应用程序。并且,通过案例具体说明了如何将这一方案应用到实际项目中。

关键词:J2EE MVC Struts Spring Hibernate

大型企业级Web应用系统的开发通常要求有一个良好的软件架构、便于协作开发和扩展升级,而传统的开发模式不能很好地满足这些要求。本文针对当前Web应用程序开发面临的问题,结合目前比较流行的开源框架SSH(Spring、Struts、Hibernate),提出一种开发J2EE 企业级Web应用的轻量级解决方案,并通过案例具体说明如何将这一方案应用到实际项目中。1 框架技术

著名的软件大师Ralph Johnson对框架(Framework)进行了如下的定义: 框架是整个系统或系统的一部分的可重用设计,由一组抽象的类及其实例间的相互作用方式组成。

框架一般具有即插即用的可重用性、成熟的稳定性以及良好的团队协作性。J2EE复杂的多层结构决定了大型的J2EE项目需要运用框架和设计模式来控制软件质量。目前,市场上出现了一些商业的、开源的基于J2EE的应用框架,其中主流的框架技术有:基于MVC模式的Struts框架和基于IoC模式的Spring框架以及对象/关系映射框架Hibernate等。1.1 表示层框架Struts

Struts是一个在JSP Model2基础上实现的MVC框架,主要分为模型(Model)、视图(Viewer)和控制器(Controller)三部分,其主要的设计理念是通过控制器将表现逻辑和业务逻辑解耦,以提高系统的可维护性、可扩展性和可重用性。Struts框架的体系结构如图1所示。

[2]

[1]

下面就图1所示的体系结构图分析Struts框架中的MVC组件。

(1)视图:视图部分主要由JSP页面组成,其中没有流程逻辑、业务逻辑和模型信息,只有标记。Struts自身包含了一组标记库(TagLib),这也是Struts的精华之一,灵活运用它们可以简化JSP页面的代码,提高开发效率。

(2)控制器:Struts中的Controller主要是其自身提供的ActionServlet。ActionServlet接收所有来自客户端的请求并根据配置文件(struts-config.xml)中的定义将控制转移到适当的Action对象。

(3)模型:Struts没有定义具体Model层的实现,Model层通常是和业务逻辑紧密相关的,有持续化的要求。目前在商业领域和开源世界,都有一些优秀的工具可以为Model层的开发提供便利。

1.2 业务逻辑层框架Spring Spring是一个解决了许多J2EE开发中常见问题并能够替代EJB技术的强大的轻量级框架。这里所说的轻量级指的是Spring框架本身,而不是指Spring只能用于轻量级的应用开发。Spring的轻盈体现在其框架本身的基础结构以及对其他应用工具的支持和装配能力。与EJB这种庞然大物相比,Spring可使程序研发人员把各个技术层次之间的风险降低。

Spring框架的核心是控制翻转IoC(Inversion of Control)/依赖注入DI(Dependence Injection)机制。IoC是指由容器中控制组件之间的关系(这里,容器是指为组件提供特定服务和技术支持的一个标准化的运行时的环境)而非传统实现中由程序代码直接操控,这种将控制权由程序代码到外部容器的转移,称为“翻转”。DI是对IoC更形象的解释,即由容器在运行期间动态地将依赖关系(如构造参数、构造对象或接口)注入到组件之中。Spring采用设值注入(使用Setter方法实现依赖)和构造子注入(在构造方法中实现依赖)的机制,通过配置文件管理组建的协作对象,创建可以构造组件的IoC容器。这样,不需要编写工厂模式、单例模式或者其他构造的方法,就可以通过容器直接获取所需的业务组件。Spring框架的结构如图2所示。

[3]

[3]

Spring框架由七个定义明确的模块组成,且每个模块或组件都可以单独存在,或者与其他一个或多个模块联合实现。Spring Core Container是一个用来管理业务组件的IoC容器,是Spring应用的核心;Spring DAO和Spring ORM不仅提供数据访问的抽象模块,还集成了对Hibernate、JDO和iBatis等流行的对象关系映射框架的支持模块,并且提供了缓冲连接池、事务处理等重要的服务功能,保证了系统的性能和数据的完整性;Sprnig Web模块提供了Web应用的一些抽象封装,可以将Struts、Webwork等Web框架与Spring整合成为适用于自己的解决方案。

Spring框架可以成为企业级应用程序一站式的解决方案,同时它也是模块化的框架,允许开发人员自由地挑选适合自己应用的模块进行开发。Spring框架式是一个松耦合的框架,框架的部分耦合度被设计为最小,在各个层次上具体选用哪个框架取决于开发者的需要。1.3 数据持久层框架Hibernate O/R mapping技术是为了解决关系型数据库和面向对象的程序设计之间不匹配的矛盾而产生的。Hibernate是目前最为流行的O/R mapping框架,它在关系型数据库和Java对象之间做了一个自动映射,使得程序员可以以非常简单的方式实现对数据库的操作。Hibernate工作原理如图3所示。

Hibernate通过对JDBC的封装,向程序员屏蔽了底层的数据库操作,使程序员专注于OO程序的开发,有助于提高开发效率。程序员访问数据库所需要做的就是为持久化对象编制xml映射文件。

底层数据库的改变只需要简单地更改初始化配置文件(hibernate.cfg.xml或者hibernate.properties)即可,不会对应用程序产生影响。

Hibernate有自己的面向对象的查询语言HQL,HQL功能强大,支持目前大部分主流的数据库,如Oracle、DB2、MySQL、Microsoft SQL Server等,是目前应用最广泛的O/R映射工具。Hibernate为快速开发应用程序提供了底层的支持。2 基于SSH组合框架的Web应用模型设计与实现 2.1 集成SSH的新型J2EE框架

前面分析了基于J2EE的三种框架技术,下面通过集成以上三种框架技术来对传统的J2EE Web开发模型加以改进,以形成一种新的、轻量型的J2EE架构。

集成SSH框架的系统框架图如图4所示,系统从职责上分为四层:表示层、业务逻辑层、[4]数据持久层和域模块层。其中使用Struts作为系统的整体基础架构,负责MVC的分离,在Struts框架的模型部分,利用Hibernate框架对持久层提供支持,业务层用Spring支持。具体做法是:用面向对象的分析方法根据需求提出一些模型,将这些模型实现为基本的Java对象,然后编写基本的DAO接口,并给出Hibernate的DAO实现,采用Hibernate架构实现的DAO类来实现Java类与数据库之间的转换和访问,最后由Spring完成业务逻辑。

系统的基本业务流程是: 在表示层中,首先通过JSP页面实现交互界面,负责传送请求(Request)和接收响应(Response),然后Struts根据配置文件(struts-config.xml)将ActionServlet接收到的Request委派给相应的Action处理。在业务层中,管理服务组件的Spring IoC容器负责向Action提供业务模型(Model)组件和该组件的协作对象数据处理(DAO)组件完成业务逻辑,并提供事务处理、缓冲池等容器组件以提升系统性能和保证数据的完整性。而在持久层中,则依赖于Hibernate的对象化映射和数据库交互,处理DAO组件请求的数据,并返回处理结果。

采用上述开发模型,不仅实现了视图、控制器与模型的彻底分离,而且还实现了业务逻辑层与持久层的分离。这样无论前端如何变化,模型层只需很少的改动,并且数据库的变化也不会对前端有所影响,大大提高了系统的可复用性。而且由于不同层之间耦合度小,有利于团队成员并行工作,大大提高了开发效率。

2.2 基于SSH框架的Web应用系统的实现

下面将通过一个实际的系统来展示如何进行基于SSH框架的Web应用开发。该系统是为某通信公司运营部开发的一个问答式系统,功能类似于百度知道和新浪爱问。由于系统的模块较多,下面就以一个用户管理模块为例来说明系统的开发实现过程,并将按照数据持久层、业务逻辑层、表示层的顺序说明系统构建过程。

(1)数据持久层

数据持久层由Java对象持久化类和数据访问对象(DAO)组成。每个数据库表都对应着一个持久化对象,这样就给予了开发者使用OO思想设计和开发的便利,同时也屏蔽了具体的数据库和具体的数据表、字段,消除了对数据库操作的硬编码在重用性上的弊端。用户信息表的部分结构如表1所示。

Hibernate通过映射(Mapping)文件将对象(Object)与关系型数据(Relational)相关联,因此需要编写和数据库表相对应的Java持久化类以及对应的映射文件。有了Java持久化类后就可以在此基础上实现数据访问类。在Spring框架中,数据访问类可以从辅助类HibernateDaoSupport继承,这极大地方便了Hibernate框架在Spring中的使用,相应的部分代码如下:

public class UserDao extends HibernateDaoSupport { public int add(User user){ return Integer.ParseInt(this.getHibernateTemplate().save(user).toString());} public List findAll(){ return this.getHibernateTemplate().loadAll(User.class);} }

具体的Hibernate数据源、session工厂、事务管理、缓冲连接池等功能都由业务层的Spring容器提供。

(2)业务逻辑层

业务逻辑层由Spring框架支持,提供了处理业务逻辑的服务组件。开发者需要对业务对象建模,抽象出业务模型并封装在Model组件中。由于数据持久层实现了Java持久化类并且封装了数据访问对象(DAO),因此可以在Model组件中方便地调用DAO组件来存取数据。Spring的IoC容器负责统一管理Model组件和DAO组件以及Spring所提供的事务处理、缓冲连接池等服务组件。

在用户管理模块中,通过业务建模创建了用户模型UserService类,封装了对用户的权限管理以及积分管理等功能。UserService类通过调用数据访问类UserDao实现对用户数据的操作。这些组件的关系将通过配置Spring框架的applicationContext.xml联系起来,配置文件的主要内容如下:

(3)表示层

表示层结合JSP和Struts的TagLib库处理显示功能,利用ActionServlet将请求(*.do)映射到相应的Action,并由Action调用业务逻辑的服务组件,然后根据处理结果跳转到Forword对象指定的响应页面。

业务流程的部署由struts-config.xml完成。下面以一个显示所有用户信息的请求(ListUser.do)为例来说明配置文件的使用。

基于J2EE的Web应用以其层次性、平台无关性的优势已经逐渐成为了电子商务、电子政务主要的解决方案。本文针对传统的J2EE Web应用开发的弊端,提出了一种利用轻量级框架来快速搭建Web应用的解决方案,并且通过其在实际项目中的应用,证明了采用此方案可以帮助开发人员在短时间内建立结构清晰、可重用性好、维护扩展方便的Web应用程序。参考文献

[1] GAMMA E, HELM R, JOHNSON R, et al.Design patterns:Elements of reusable object-oriented software[M].Addison Wesley, 1994.[2] 孙卫琴.精通Struts:基于MVC的Java Web设计与开发[M].北京:电子工业出版社,2004.[3] JOHNSON R, HOELLER J, ARENDSEN A, et al.Java/J2EE application framework reference document.V1.1.2004.[4] 徐长盛,戴超.一种快速开发Web应用程序方法的研究[J].计算机工程与设计,2004,(12):2237-2239.[5] 夏昕,曹晓钢,唐勇.深入浅出Hibernate[M].北京:电子工业出版社,2005.[6] JOHNSON R.Expert one-on-one J2EE design and development[M].魏海萍译.北京:电子工业出版社,2003.在用ssh开发web应用时,需要对生成的各个类文件进行组织,下面就对一个可行的目录方案进行介绍:

譬如应用中有一个用户管理模块,则在公共包下建立一个user包,如该公共包可以为com.simon.oa,在user包下包括如下子包

1、controler包

该包放置各种struts的action。

2、dao包

该包放置各类dao(data access object),也就是放置对数据库访问的实现类,在用myeclipse中的“Hibernate Reverse Engineering”进行反向操作时在某一个目录中就会生成对应某个表的DAO,生成后可将该DAO拖到dao包中。在某些应用中将DAO作为接口,在该接口中包括所有对数据库的操作方法,然后在dao包建立一个hibernate包,在hibernate包中放置对DAO接口的实现,譬如:UserDAO接口有一个实现类为UserDaoImpl,将该类放置到hibernate包中,实际的开发倾向于后一种方式,因为对这个DAO接口可以实现spring的IoC操作。(不知道myeclipse对此是怎么考虑的,这个问题让我纠缠了很久,误将DAO理解成一个能够进行实际操作的类,而不是一个接口,以后开发要注意)

3、model包

该包中放置hibernate反向工程生成的bean和该bean对应的.hbm.xml文件。

4、service包 该包放置业务操作类,譬如用户服务类,一般情况将该用户操作类提取一个接口,然后在service包下生成一个impl包,在impl包中才放置用户操作接口的实现类。该用户接口实现类中调用DAO接口对数据库进行操作,而调用该实现类的方法在struts的action中。

5、vo包(value object)

vo包中的中包括struts中使用的POJO及actionform等信息。VO: Value Object DTO: Data Transfer Object 个人理解VO和DTO是类似的东西,原则上VO和DTO只有Public Fields,主要用于进程之间数据传递的问题,VO和DTO不会传递到表示层,在业务层就会被吸收。但看到很多人在建立VO和DTO时,也含有Setter,Getter属性和一些其它的辅助方法,这也无可厚非,我自己也不能确定这对不对。posted

第二篇:java的SSH框架总结(范文)

对于java中SSH框架的理解

SSH 是指 Struts+ spring+ hibernate 的一个集成框架,这是一种比较流行的java web应用程序开源框架。

Struts

Struts是一个基于Sun J2EE平台的MVC框架,主要采用Servlet和JSP技术来实现的。由于Struts能充分满足引用开发的需求,简单易用,敏捷迅速,所以很受关注。Struts 吧Servlet、JSP、自定义标签和信息资源(message resource)整合到一个统一的框架中,开发人员利用其进行开发室不用再自己编写实现全套的MVC模式,极大的节省了时间。

Spring Spring是一个解决了许多在J2EE开发中常见的问题的强大框架。Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯。

Spring的架构基础是基于JavaBean属性的Inversion of Control 容器。然而,这仅仅是完整图景中的一部分:在Spring使用IOC容器作为构建完关注所有架构层的完整解决方案是独一无二的。Spring提供了唯一的数据访问抽象,包括简单和有效率的JDBC框架,极大的改进了效率并且减少了可能的错误。Spring的数据访问架构还集成了Hibernate 和其他O/R mapping 解决方案。Spring还提供了唯一的事物管理抽象。它能够在各种底层事务管理技术,例如JTA 或者JDBC事务提供一个一致的编程模型。Spring提供了一个标准Java语言编写的AOP框架,他给POJOs提供了声明式的事务管理和其他企业事务——如果有必要还可以实现自己的aspects。这个框架提供了可以和IOC容器集成的强大而灵活的MVC web框架。

Hibernate Hibernate 是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,是的java程序员可以随心所欲的适用对象编程思维来操控数据库。Hibernate 可以应用在任何使用JDBC的场合,既可以在java客户端程序中使用,也可以在Servlet/jsp的web应用中使用,其最具革命性意义的是:Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。

在SSH的组合框架模式中,三者各自的作用 Struts 是一个很好的MVC框架,主要技术是Servlet和JSP。Struts的MVC设计模式可以让我们的逻辑思维变得很清晰,让我们写程序层次分明。

Spring提供了管理业务对象的一致方法,并鼓励注入对接口编程而不是对类编程的良好习惯,使我们的产品在最大程度上解耦。

Hibernate 是用来持久化数据的,提供了完全面向对象的数据库操作。Hibernate对JDBC进行了非常轻量级的封装,使得他与关系型数据库打交道变得非常轻松。

负责Web层:

ActionFormBean接收网页中表单提交的数据,然后通过Action进行处理,再Forward到对应的网页,在Struts-config.xml中定义了,ActionServlet会加载进来。

Spring负责业务层管理,即Service:

Service为Action提供统一的调用接口,封装持久层的DAO,并集成Hibernate,Spring可对JavaBean和事物进行统一管理。

Hibernate负责持久层,完成数据库的CRUD操作:

Hibernate有一组hbm.xml文件和PO,是与数据库中的表相对应的,然后定义DAO,这些是与数据库打交道的类。

在Struts+Spring+Hibernate系统中,对象之间的调用流程如下:

Struts——>Spring——>Hibernate

JSP——>Action——>Service——>DAO——>Hibernate

第三篇:基于SSH框架的学生档案信息管理系统

毕业设计(论文)

基于SSH框架的学生信息管理系统

别 : 计算机科学与技术系

专业(班级): 计算机科学与技术(2011级1班)作者(学号): 指导教师: 完成日期:

陈洪(51102011007)

顾珺、李铁柱

2015年4月15日

蚌埠学院教务处制

目录

摘 要........................................................................................................................Abstract....................................................................................................................1 概 述..................................................................................................................1.1 项目简介............................................................................................................1.1.1 研究背景.........................................................................................................1.1.2 项目开发目的.................................................................................................1.1.3 项目开发的意义.............................................................................................2 开发工具及相关简介........................................................................................2.1 SSH框架简介....................................................................................................2.2 Jsp技术简介......................................................................................................2.3 MySQL数据库简介..........................................................................................2.4 Tomcat 6.0介绍..................................................................................................2.5 MyEclipse的简介..............................................................................................3 可行性分析........................................................................................................3.1 技术可行性........................................................................................................3.2 经济可行性........................................................................................................3.3 社会可行性........................................................................................................3.3.1 法律因素.........................................................................................................3.3.2 用户使用可行性.............................................................................................4 需求分析............................................................................................................4.1 功能分析............................................................................................................4.1.1 管理员模块.....................................................................................................4.1.2 教师模块.........................................................................................................4.1.3 学生模块.........................................................................................................4.2 系统分析............................................................................................................4.2.1 业务流程分析.................................................................................................4.2.2 功能流程分析...............................................................................................5 总体设计..........................................................................................................5.1 系统功能设计..................................................................................................5.2 数据库设计....................................................................................................5.2.1 概念结构设计...............................................................................................5.2.2 管理员实体属性图.......................................................................................5.2.3 教师实体属性图...........................................................................................5.2.4 学生实体属性图...........................................................................................5.2.5 公告实体属性图...........................................................................................5.2.6 成绩实体属性图...........................................................................................5.2.7 E-R模型的组成元素....................................................................................5.3 数据库表设计..................................................................................................5.3.1 管理员信息表...............................................................................................5.3.2 教师信息表...................................................................................................5.3.3 学生信息表...................................................................................................5.3.4 成绩信息表...................................................................................................5.3.5 公告信息表...................................................................................................5.4 系统开发工具与开发模式的选择..................................................................5.4.1 系统开发工具...............................................................................................5.4.2 系统设计模式...............................................................................................6 详细设计............................................................................................................6.1 系统登录模块..................................................................................................6.1.1 登录模块.......................................................................................................6.2.1 基础信息管理界面.......................................................................................6.2.2 个人信息管理界面.......................................................................................6.2.3 课程管理界面...............................................................................................6.2.4 录入教师信息界面.......................................................................................6.2.5 录入学生信息界面.......................................................................................6.3 教师用户模块..................................................................................................6.3.1 个人信息管理界面.......................................................................................6.3.2 查看公告信息界面.......................................................................................6.3.3 学生成绩管理界面.......................................................................................6.4 学生登录模块..................................................................................................6.4.1 查看个人信息界面.......................................................................................6.4.2 课程查询界面...............................................................................................6.4.3 学校公告界面...............................................................................................6.4.4 我的成绩界面...............................................................................................7 软件测试与分析..............................................................................................7.1 软件测试的重要性..........................................................................................7.2 系统的实际测试..............................................................................................7.3 测试环境与测试条件......................................................................................7.4 系统运行情况..................................................................................................8 结

论..............................................................................................................8.1 系统的优势......................................................................................................8.2 系统的不足......................................................................................................8.3 总结..................................................................................................................致

谢....................................................................................................................参 考 文 献..........................................................................................................蚌埠学院毕业设计(论文)

基于SSH框架的学生信息档案管理系统

摘要:由于现在高校招生率的提高,各大高校的学生数量普遍增多,随之增加的就是学生档案信息。面对如今繁杂庞大的信息数据库,传统的手工记录的管理方式显得力不从心。伴随着网络信息技术在教育事业上的应用,学生档案管理相应而出,使得学生档案的管理比以前更方便。本文就此系统做了全面的解析概述,以及每个功能所应用的核心技术及其运用方法,整体结构方法也做了全面介绍。本系统以Myeclipse 2014做为开发工具,用作支持本系统的数据库是MySQL,服务器选择的是Tomcat 6.0,Jsp和Servlet技术用作前台开发手段[1],总体框架采用SSH架构。项目总体分为前、后台两个部分,前台提供管理员、教师用户和学生用户的登录。教师用户的主要职责是评定学生的考试成绩,此外还可以对个人信息和公告信息进行查看;学生用户可以查看个人信息、课程信息、公告信息和个人成绩;管理员则从后台登录,管理数据库中的相关信息如对学生用户和教师用户的添加,以及对公告信息的调整。

关键词:SSH框架;MyEclipse;MySQL;Tomcat;Jsp

陈洪:基于SSH框架的学生档案信息管理

Students Information File Management System Based on SSH Framework Abstract: Now that increase college enrollment rates, the number of students in major universities generally increased, increased is the student profile information.Today the face of huge information database complexity, the traditional manual records management appeared to be inadequate.Along with the network of information technology, student records management in the education of corresponding out, making the management of student records and more convenient than ever.In this paper, this system made a comprehensive analysis overview, and each function is applied the core technology and its application method, the overall structure of methods to do a comprehensive introduction.This system Myeclipse 2014 as a development tool, used to support the system's database is MySQL, the server is selected Tomcat 6.0, Jsp and Servlet technologies used as foreground development tools, the overall framework architecture using SSH.The overall project is divided into front, back two parts, the front desk manager, teacher and student user to provide the user's login.Teachers users to view personal information, student information and post information, modify personal information, as well as courses for student achievement rates;student users can view personal information, course information, announcements and personal achievement;background provide administrator login, database management for the information of student, teacher and so on[2].Keywords: SSH Framework;MyEclipse;MySQL;Tomcat;Jsp

蚌埠学院毕业设计(论文)开发工具及相关简介

2.1 SSH框架简介

SSH框架包括了Struts、Spring以及Hibernate,是目前使用相对广泛的一个Web开源架构[3]。

SSH框架结构清晰,大体可分为表示层、业务逻辑层、数据持久层和域模块层,各层之间有很好的关联。该框架有诸多的优点,如有较强的可复用性,能够帮助使用者更为清晰的搭建需要使用的架构,而且可维护性好。本系统中的Struts框架采用的是Struts2,主要用在系统的业务逻辑层,负责业务的跳转;Hibernate框架主要是负责对数据库进行轻量级封装,做持久化处理,可以减少SQL语句的编写;Spring框架则是Struts和Hibernate框架的管理者[4]。SSH框架的实现方法是通过配置相关的xml文件,然后导入一些所需要的jar包,然后对这些jar包进行调用。

2.2 Jsp技术简介

Jsp是SUN公司和许多公司一起建立的一种动态技术标准。Jsp网页的组成其实是在原本网页中的Html文件中加入了Jsp标签和相关Java程序片段从而形成了如今Jsp网页[5]。Jsp技术的最大特点就是它的所有操作都能在服务器端的浏览器上进行,然后将运行的结果反馈给用户,这样就会很大程度降低对用户的客户端浏览器的要求。

Jsp技术是Java Servlet API的扩展。Jsp页面通常由静态Html/XML组件、自定义Jsp标签和成为scriptlet的Java代码片段组成。Jsp技术是建立在Servlet基础上的,两者的执行都是在服务器端的,用户可以通过浏览器直接进行访问执行。当服务器端出现访问请求超时时,其中的Java程序会首先被执行,之后将执行结果返回给用户,一并返回的还有相关的Html代码。通常的情况下Jsp页面很少去操作后台的数据,Jsp页面只是用来提取输入到网页上的数据和解决网页的静态化页面,至于业务处理则毫无干系。若想要对数据库进行操作或者对网页重定向以及发送E-mail,都是通过向网页中插入Java代码来实现,其它所需功能也都可以通过此方法实现。

陈洪:基于SSH框架的学生档案信息管理

2.3 MySQL数据库简介

MySQL的开发者是瑞典的MySQL AB公司,它是一个免费开源的数据库,对于Windows、Linux等操作系统都适用;此外,MySQL对于网络也是完全适用的,也就是说用其构建的数据库可以被网上的任何服务器进行访问[6]。MySQL具有十分强大的功能,操作又十分简单,而且有较强的安全可靠性,运行速度方面也不会让人失望,也比较容易管理。除了以上特点,MySQL最大的优点就是它是一个免费开源软件!而且能够直接从网上下载到与其相匹配的第三方工具软件对其操作。在诸如Unix这样的操作系统上MySQL可以直接下载它的服务器和客户端软件。如果是在Windows系统上,MySQL数据库的客户机和客户机程序也都是免费的,这就是MySQL最大的优势。

2.4 Tomcat 6.0介绍

Tomcat服务器是由Apache Software Foundation(Apache软件基金会)中Apache Group Jadarta开发小组开发的一个免费的开放源代码的服务器软件[7]。Tomcat能够完全兼容Jsp和Servlet的最新规范,这都得力于SUN公司的支持。它的不足之处就是它的配置比较繁琐,而且还具有一些安全问题,但是这些缺点丝毫不会影响它在开发者心中的地位,Tomcat先进的技术,出色的稳定性和兼容性,以及最为人性化的免费政策都是深受开发者喜爱的原因,成为应用最为广泛的WEB应用服务器软件。

2.5 MyEclipse的简介

MyEclipse是一个企业级的工作平台,它的前生只是Eclipse的一个插件[8],但是如今却发展成为比Eclipse功能更为强大的工作平台。它是Eclipse的扩展,对Eclipse的功能有全面性的完善,其中就包括了完备的编码,调试、测试和发布功能。利用它可以在数据库和JavaEE(Java Enterpride Edition)的开发、发布以及应用程序服务器的整合方面大大提高了工作效率,能丰富JavaEE集成开发环境。

在MyEclipse组件中,更为方便地提供了Jsp、Servlet、HTML、XML、Struts、Hibernate、Spring等框架的开发支持,而随着不断衍生发展的新技术,MyEclipse也在不断的发展[9]。

蚌埠学院毕业设计(论文)需求分析

4.1 功能分析

4.1.1 管理员模块

系统管理员可以修改个人密码,添加修改课程信息、系别信息以及公告信息,此外还可以浏览学生基本信息和成绩。

4.1.2 教师模块

本系统中的教师用户的主要职责是对学生成绩进行评定,给出相应分数,然后可以根据课程信息和考试时间对考试成绩查看。另外,可以对相关信息进行查看,如个人信息、公告信息和学生信息等。

4.1.3 学生模块

学生模块实现的有查看个人信息、课程信息、考试成绩和公告信息,此外可以添加自己的相关课程。

4.2 系统分析

4.2.1 业务流程分析

所谓业务流程分析是指在进行设计开发之前,对自己的系统设计按照所给要求进行相关的业务处理,设计好系统的总体框架,根据实际功能需要进行相关的业务分析,对各个业务流程进行详细分析,如业务内容、处理所需的大致时间等,此外对各个业务流程所需的信息来源、信息处理的方法也都要有相对应的总结,这样才能更好的进行开发。

业务流程分析就是为了让开发者能够更好的了解系统的开发方向以及相关的流程处理,帮助开发者梳理清楚开发思路,使系统开发更有条理。一下是系统的流程图。

具体业务流程如图4-1所示。

陈洪:基于SSH框架的学生档案信息管理

学学学学学学学学学学学学学学学学学学学学学学

图 4-1 业务流程图

4.2.2 系统功能流程分析

功能流程分析能够让开发者对自己的系统中各个角色的功能之间的关系更加明了,这让系统更加结构化,在开发的同时自己在大脑中能够有一个明确的构思,有一个清晰的开发方向。

下面将具体分析学生角色和管理员之间的关系,因为教师与管理员之间的关系与此基本相似,所以就不一一列出。

具体功能流程图如图4-2所示:

0-

陈洪:基于SSH框架的学生档案信息管理 总体设计

5.1 系统功能设计

系统设计是一个把功能需求转换成用设计程序表示的过程。系统设计时需要事先对要实现的目标系统进行分析研究,之后总结出一套系统的设计规划,以便能够有计划地设计系统。对于本系统来说,设计之前就要对学生档案信息管理系统进行全方位的调查总结,然后绘制一个系统的总体规划。系统设计包括系统总体设计、系统详细设计、系统数据库设计、系统开发工具、开发技术和开发模式等[8]。

从数据流图出发,对数据流图进行分析,如图5-1:

后台功能模块老师模块管理员模块学生模块个人信息学生成绩系统公共个人信息学院管理系别管理班级管理课程管理班级管理学生管理公共管理个人信息我的成绩系统公共

图5-1 学生信息管理系统功能模块图

5.2 数据库设计

本系统主的功能实现主要围绕数据库展开的,所以本系统的核心就是数据库。数据库的设计直接影响本设计各项功能的进行,是本设计的基础,就像是房子的根基一样,它的稳固与否直接影响整个建筑的施工,所以在设计本系统的数据库的时候非常的细心,不能出现任何漏洞。

5.2.1 概念结构设计

从数据需求分析中得出系统的实体属性图。

陈洪:基于SSH框架的学生档案信息管理

级、年龄等。

如图5-4所示:

开始用户登录用户名密码是否正确N返回登录页面Y进入主页面结束

图5-4学生实体属性图

5.2.5 公告实体属性图

公告实体属性图描述的是公告信息,包括公告编号、标题、内容、时间等。如图5-5所示:

开始用户登录用户名密码是否正确N返回登录页面Y进入主页面结束

图5-5公告实体属性图

5.2.6成绩实体属性图

成绩属性图描述的是学生的成绩信息,包括成绩编号、学生编号、成绩、考核时间等。

如图5-6所示:

陈洪:基于SSH框架的学生档案信息管理

开始用户登录用户名密码是否正确N返回登录页面Y进入主页面结束

图5-7系统E-R图

5.3 数据库表设计

5.3.1 管理员信息表

管理员信息表用来存放管理员信息,其中包括管理员编号、用户名和用户密码。具体信息如表5-1所示:

表5-1管理员信息表

字段名 id name pwd

类型 Int varchar varchar

长度 4 30 20

说明

管理员编号(主键)

用户名 用户密码

5.3.2 教师信息表

教师信息表用来存放教师信息,包括教师编号、密码、姓名、年龄、电话等。具体信息如表5-2所示:

陈洪:基于SSH框架的学生档案信息管理

具体信息如表5-4所示:

表5-4成绩信息表

字段名 id student_id course_id Grade Time Beizhu

类型 Int Int Int Int Datetime varchar

长度 4 4 4 4 8 50

说明 成绩编号(主键)学生学号(外键)考核类型编号(外键)

成绩 考核时间 备注

5.3.5 公告信息表

公告信息表用来存放公告信息,包括公告编号、标题、内容、时间等。具体信息如表5-5所示:

表5-5公告信息表

字段名 id Title Content Time

数据类型 Int varchar varchar Datetime

长度 4 20 100 8

功能描述 编号(主键)

标题 内容 时间

5.4 系统开发工具与开发模式的选择

5.4.1 系统开发工具

本系统主要的架构使用的是SSH框架,结合Jsp技术对前端的设计进行的系统开发。Jsp技术安全性较高,可随处运行,并且与各个开发软件兼容;SSH框架则为开发者提供了一个系统的总体框架,让开发者的工作更加系统性的进行,其中Struts2作为系统的基础框架,也就是为系统搭建一个大致的架构,Hibernate则是负责连接数据库的,通过Spring框架对这两个框架进行管理,让

陈洪:基于SSH框架的学生档案信息管理

综上所述,本系统所采用的B/S架构也是现在较为流行的开发架构相对于其他架构有着不容忽视的优势,这也将会是将来开发模式的主要发展趋势。

0-

陈洪:基于SSH框架的学生档案信息管理

图6-2 登录失败

具体流程如图6-3所示:

开始用户登录用户名密码是否正确N返回登录页面Y进入主页面结束

图6-3 登录程序流程图

陈洪:基于SSH框架的学生档案信息管理

如图6-6所示:

图6-6 课程管理界面

6.2.4 录入教师信息界面

这是录入教师信息的功能界面,如图6-7所示:

图6-7录入教师界面

6.2.5录入学生信息界面

这是录入学生信息的功能界面,如图6-8所示:

陈洪:基于SSH框架的学生档案信息管理

6.3.3 学生成绩管理界面

教师可以按照考试课程、考试时间和考试类型录入学生成绩信息,如图6-11所示:

图6-11学生成绩管理界面

6.4 学生登录模块

6.4.1 查看个人信息界面

学生可以查看个人信息。如图6-12所示:

图6-12 个人信息界面

6.4.2 课程查询界面

学生可以查看课程信息,如图6-13所示:

陈洪:基于SSH框架的学生档案信息管理 软件测试与分析

系统测试是设计的最后一项,也是至关重要的一项,只有测试通过新的系统才算完成,所以测试在开发过程中也占有举足轻重的地位。软件测试有专门的测试人员负责,这和开发人员的工作是完全不同。如今的软件测试趋向于开发的每个阶段都应该包含测试,该观点的依据是早发现问题早解决,这样也可以防止影响到后续工作的进行。

7.1 软件测试的重要性

软件测试在整个的软件开发中占有着重要的地位,这是软件交付于客户之前最后的检测手段。就相当于汽车量产之前的撞墙检查一样,这也是从用户的“安全问题”考虑。所谓的软件测试就是在运行成功的程序上寻找Bug,检测出的错误一般都是运行时不会出现的,也是开发人员看不出来的,这就是所谓的Bug。而现在推崇的逐步测试是在开发的每个阶段都进行测试,这样能更好的消除开发过程中所遇到的问题,更好的完成开发。

实际上,对于一个软件的开发来说,不论具有多么熟练的开发技术、采用怎样完善的方法,都会有错误产生。开发人员能够做到的只能是减少错误的引入而不能杜绝错误的产生,这些引入的错误就需要测试来将其找出来,而软件中的错误的数量也是需要通过测试计算的,所以说测试在软件开发中占有着举足轻重的地位。只要有开发有程序就一定会有测试。而且据统计表明,在系统的开发中,并不是大家想的测试肯定比开发工作量小,这恰恰是相反的,测试的工作量一般情况下都会比开发的工作量多40%。而且在开发中,测试的成本也是占有很大部分的,一般来说都会占有30%到50%。如果把维护阶段也考虑在内,讨论整个软件生存期时,测试的成本比例也许会有所降低,但实际上维护工作相当于二次开发,乃至多次开发,其中必定还包含有许多测试工作。

7.2 系统的实际测试

软件测试主要分为黑盒测试和白盒测试。黑盒测试:也称功能测试,数据驱动测试等,它将待测对象堪称是一个黑盒子,在完全不考虑程序的内部结构和特性的情况下,只依据规格说明书检查程序的功能是否能正常使用[15]。白盒测试:

陈洪:基于SSH框架的学生档案信息管理 结

8.1 系统的优势

本系统是针对学生档案信息的管理而开发,为了让管理者更为轻松的管理学生档案信息。本系统能够条理化的录入学生信息、教师信息、课程信息和公告信息,相比传统方式更加便捷;在查询时,可以根据个人需要的条件进行查询,如:根据学生学号查询学生成绩,根据课程信息查询所有该课程的学生成绩等;管理时管理员只需要对后台数据库进行管理,面对庞大的数据也可以轻松应对。

8.2 系统的不足

所谓人无完人,本系统也有不足之处,例如系统采用B/S架构开发,所以管理工作只能在浏览器上进行,没有客户端方便;系统目前只支持Tomcat 6.0服务器;系统目前只有对数据信息的基本增删改查功能,在以后的学习中一定对其完善。

8.3 总结

经过这几个月的系统开发,让我获益匪浅。由于之前对SSH架构掌握的不是很熟练,所以在开发过程中也在自学,这也算是自学成功的劳动成果。在整个设计过程中,由主体SSH框架引申开展的一系列功能均能良好实现。此外,在开发过程中也对之前的Jsp技术和MySQL数据库的相关知识复习,在运用起来更为熟练。在通过开发后期对系统的调试后,系统功能正常运行,基本功能都顺利实现。而且本系统界面美观,操作方便,符合大众要求。不过部分细节可能由于时间仓促加上系统开发经验上的经验不足,系统在设计过程中不可避免地遇到了一些诸如以下的一些问题,如:

(1)起初对数据库的构建不够完善,导致开发初期的部分数据取不到值;(2)在前端页面的跳转中,由于页面较多,出现了一些跳转错误;(3)在测试阶段,在使用了Tomcat7.0服务器出现了Session error的错误。不过在后期的系统完善方面,这些问题都受到了重视,也都得到了解决,使得本系统真正的符合了开发者和用户的需求,也更加规范、科学。

0-

陈洪:基于SSH框架的学生档案信息管理

参 考 文 献

[1] 刘佳.基于JSP&Servlet图书信息管理系统的设计与实现[D].天津大学,2012.[2] Peluso M, Takizawa P.Student involvement in the development of integrated curricula.[J].Medical Education, 2010, 44(11):1120–1121.0.[3] 马铎.基于SSH技术的小区车辆管理系统设计与实现[J].信息与电脑:理论版, 2013,(3).[4] 李宁.Java Web编程实战宝典[M].北京:清华大学出版,2014: 41.[5] 包子建.基于B/S模式和JSP技术的教师办公管理系统的设计与实现[D].华东师范大学, 2006.DOI:10.7666/d.y1015368.[6] 王飞飞.MySQL数据库应用从入门到精通[M].北京:中国铁道出版社,2014: 36.[7] 李鉴.开源技术Struts、Spring、Hibernate在MIS开发中的应用研究[D].北方民族大学, 2008.[8] 曹大有, 王瑜.基于MyEclipse的Hibernate持久层框架的开发过程[J].计算机系统应用, 2007,(12):101-104.DOI:10.3969/j.issn.1003-3254.2007.12.025.[9] 张晓梅.基于J2EE的教学实验管理系统的设计与开发[D].山东大学, 2006.DOI:10.7666/d.y982177.[10] 年轶, 林琳.E-R图向关系模型转换规则的研究[J].微型电脑应用, 2004, 20(1):12-14.DOI:10.3969/j.issn.1007-757X.2004.01.002.[11] 李宁.Java Web编程实战宝典[M].北京:清华大学出版,2014: 72.[12] 王飞飞.MySQL数据库应用从入门到精通[M].北京:中国铁道出版社,2014: 36.[13] CSDN博客频道.关于B/S架构和C/S架构探析[J].2006.http://blog.csdn.net/yuelengxin/article/details/593561.[14] 王宇.无线局域网基本原理及前沿应用[J].中国数据通信,2003,5(8):34-39.[15] 萨默维尔.软件工程(第九版)[M].北京:机械工业出版社,2011: 78-81.2-

第四篇:色彩构成小结

《色彩构成》学习小结

在经过了平面构成的学习之后,我们又开始了色彩构成的学习。对于色彩构成,它不只向平面构成那样只是通过点线面以及明暗来表现画面的美感,而是在此基础上又增添了色彩的结构,这使得画面更具有鲜明的美感。

对于色彩构成,它有别于一般色彩写生,而强调全面了解掌握色彩基本知识,侧重于对色彩规律的科学训练与主观运用,其目的是更有效地应到我们观察学习自然知识,启发创作灵感,执导作品实践。

在色彩学习过程中,我们涉及到了色彩学的结构体系。即人类生活经验及色彩应用的各方面构筑的结构体系,色彩文化史、地域文化色彩、宗教文化色彩、民俗学习过程中色彩等。还有色彩的美学、色彩心理学、色彩与社会、色彩与自然、色彩与艺术等。色彩的构成艺术,人类创造的造型视觉色彩艺术,自然界物质色彩艺术规律等。同时色彩构成:即色彩的相互作用,是从人对色彩的知觉和心理效果出发,用科学的分析方法,把复杂的色彩现象还原为基本要素,利用色彩在空间量与质上的变幻性,按照一定的规律去组合各构成之间的关系,再创造新的色彩效果的过程。

在学习色彩构成的过程中不仅让我学到新的知识还让我能够了解到以前所模糊的知识。,我以前认为光的三原色与色彩的三原色相同。而在色彩的基本原理学习中我却了解到了色素的三原色分别是品红、黄、青,对于光的三原色则是红、绿、蓝。这在以前的学习中,我是经常把它们搞混淆的。而另一方面色彩的原色,以及混合色等。在色彩学习中,我最感兴趣的是色彩对比。其中分为高调,中调,低调这三种。而在每一种中又分三个长调、中调、短调,例如在高调中有高长调、高中调、高短调。其他的各调子也是如此。不同的调子给人以不同的感觉如高长调给人积极、明快、活泼、刺激等感觉。在对比的学习中还有同类色对比;类似色对比;邻近色对比。同时纯度的对比;冷暖对比;色度对比;形状对比;面积对比等。值得一提的是在面积对比中在不同颜色的情况下同面积对比效果强烈,而在不同面积的情况下则较弱。

色彩还给人情感的变化,一、色彩的视觉形象。

二、色彩的心理形象。

三、色彩的联想。

四、色彩的象征。有意思的是在色彩的情感中会给人带来色彩的错视效果,它又分为同时对比的错视形象和连续对比的错视形象。色彩给人的心理

感知有色彩的冷暖,以及膨胀收缩感、轻重感、软硬感等。之所以有这些感觉不是由于色彩的本身原因,而是人们的主观感觉以至于产生心里的联想。而其联想又有具体联想,抽象联想和共感联想。在色彩的象征中本人最喜欢的红色为兴奋色。

对于色彩的意义,在审美方面色彩是人类表达情感的语言手段。色彩作为情绪信息的载体传递与文化背景,历史延续,意识观念,传统习俗,风土人情,生活方式有关。色彩设计的意义其要解决的是创造个性化的色彩综合美,是将符合艺术规律的色彩结合应用于我们的设计实践中去。

第五篇:struts2代码分析

1.Struts2架构图和请求处理流程

请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。

ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用Interceptors,执行Action本身,创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。

2.Struts2部分类介绍

这部分从Struts2参考文档中翻译就可以了。

ActionMapper

ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docs¥actionmapper.html。

ActionProxy&ActionInvocation

Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。

ConfigurationProvider&Configuration

ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。

3.Struts2请求流程

1、客户端发送请求

2、请求先通过ActionContextCleanUp-->FilterDispatcher

3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action

4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行

5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类

6、ActionProxy创建一个ActionInvocation的实例

7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用

8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现。

首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.接下来就从Dispatcher开始看起,先看其构造函数:

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

我们再看在FilterDispatcher创建Dispatcher的:

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

创建Dispatcher之后,来看init()方法

init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.主要分七步走,看下面注释

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager

=

new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

}

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager

=

new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

throw

}

new ConfigurationException(“Could not find or error in org/apache/struts2/default.properties”, e);

loadSettings(props, defaultSettings);

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings =

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

settings.getImpl(name),// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

再来看第二步:init_TraditionalXmlConfigurations()

private void init_TraditionalXmlConfigurations(){

settings.getImpl(name), //首先读取web.xml中的config初始参数值

//如果

使

认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

private void init_TraditionalXmlConfigurations(){

//首先读取web.xml中的config初始参数值

//如果

使

认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

对于其它配置文件只用接口。

类XmlConfigurationProvider负责配置文件的读取和解析,首先通过init()中的loadDocuments(configFileName);利用DomHelper中的

public static Document parse(InputSource inputSource, Map dtdMappings)将configFileName配置文件通过SAX解析方式按照DtdMappings解析成Document对象.然后通过Provider的register()方法加载“bean”和“constant”属性,再通过loadPackages()加载package及package中的属性

addAction()方法负责读取标签,并将数据保存在ActionConfig中; addResultTypes()方法负责将标签转化为ResultTypeConfig对象; loadInterceptors()方法负责将标签转化为InterceptorConfi对象;

loadInterceptorStack()方法负责将标签转化为InterceptorStackConfig对象;

StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProviderloadInterceptorStacks()方法负责将标签转化成InterceptorStackConfig对象。

而上面的方法最终会被addPackage()方法调用,addPackage又会被Provider的loadPackages()调用,将所读取到的数据汇集到PackageConfig对象中。

protected PackageConfig

addPackage(Element

packageElement)

throws ConfigurationException {

PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if(newPackage.isNeedsRefresh()){

return newPackage.build();

}

// add result types(and default result)to this package

addResultTypes(newPackage, packageElement);

// load the interceptors and interceptor stacks for this package

loadInterceptors(newPackage, packageElement);

// load the default interceptor reference for this package

loadDefaultInterceptorRef(newPackage, packageElement);

// load the default class ref for this package

loadDefaultClassRef(newPackage, packageElement);

// load the global result list for this package

loadGlobalResults(newPackage, packageElement);

// load the global exception handler list for this package

loadGobalExceptionMappings(newPackage, packageElement);

// get actions

NodeList actionList = packageElement.getElementsByTagName(“action”);

for(int i = 0;i < actionList.getLength();i++){

Element actionElement =(Element)actionList.item(i);

addAction(actionElement, newPackage);

}

// load the default action reference for this package

loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();

configuration.addPackageConfig(cfg.getName(), cfg);

return cfg;

}

loadConfigurationFiles解析读取xml中的内容

private List

loadConfigurationFiles(String

fileName,Element includeElement){

...//通过DomHelper调用SAX进行解析xml

doc = DomHelper.parse(in, dtdMappings);

...Element rootElement = doc.getDocumentElement();

NodeList children = rootElement.getChildNodes();

int childSize = children.getLength();

for(int i = 0;i < childSize;i++){

Node childNode = children.item(i);

if(childNode instanceof Element){

Element child =(Element)childNode;

final String nodeName = child.getNodeName();

if(“include”.equals(nodeName)){

String includeFileName = child.getAttribute(“file”);

//解析每个action配置是,对于include文件可以使用通配符*来进行配置

//如Struts.xml中可配置成

if(includeFileName.indexOf('*')!=-1){

ClassPathFinder wildcardFinder = new ClassPathFinder();

wildcardFinder.setPattern(includeFileName);

Vector wildcardMatches = wildcardFinder.findMatches();

for(String match : wildcardMatches){

//递归Load子file中的

docs.addAll(loadConfigurationFiles(match, child));

}

} else {

docs.addAll(loadConfigurationFiles(includeFileName, child));

}

}

}

}

docs.add(doc);

loadedFileUrls.add(url.toString());

...return docs;

}

首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.接下来就从Dispatcher开始看起,先看其构造函数:

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方

public Dispatcher(ServletContext servletContext, Map initParams){

this.servletContext = servletContext;

//配置在web.xml中的param参数

this.initParams = initParams;

}

我们再看在FilterDispatcher创建Dispatcher的:

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

protected Dispatcher createDispatcher(FilterConfig filterConfig){

Map params = new HashMap();

for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

String name =(String)e.nextElement();

String value = filterConfig.getInitParameter(name);

params.put(name, value);

}

都可以从FilterConfig中得到

return new Dispatcher(filterConfig.getServletContext(), params);

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

创建Dispatcher之后,来看init()方法

init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.主要分七步走,看下面注释

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

new

}

public void init(){

if(configurationManager == null){

//设置ConfigurationManager的defaultFrameworkBeanName.//这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等

configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

}

//读取properties信息,默认的default.properties,init_DefaultProperties();// [1]

//读取xml配置文件

init_TraditionalXmlConfigurations();// [2]

//读取用户自定义的struts.properties

init_LegacyStrutsProperties();// [3]

//自定义的configProviders

init_CustomConfigurationProviders();// [5]

//载入FilterDispatcher传进来的initParams

init_FilterInitParameters();// [6]

//将配置文件中的bean与具体的类映射

init_AliasStandardObjects();// [7]

//构建一个用于依赖注射的Container对象

//在这里面会循环调用上面七个ConfigurationProvider的register方法

//其中的重点就是DefaultConfiguration的#reload()方法

Container container = init_PreloadConfiguration();

container.inject(this);

init_CheckConfigurationReloading(container);

init_CheckWebLogicWorkaround(container);

if(!dispatcherListeners.isEmpty()){

for(DispatcherListener l : dispatcherListeners){

l.dispatcherInitialized(this);

}

}

new

}

分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.下面将分析这七层功夫是怎样一步步练成的.首先是init_DefaultProperties()

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

private void init_DefaultProperties(){

configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

}

接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

register()方法

public void register(ContainerBuilder builder, LocatableProperties props)

throws ConfigurationException {

Settings defaultSettings = null;

try {

defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

} catch(Exception e){

throw

}

loadSettings(props, defaultSettings);

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

new

ConfigurationException(“Could

not

find

or

error

in org/apache/struts2/default.properties”, e);

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

props.setProperty(name, settings.getLocationImpl(name));

}

}

//PropertiesSettings构造方法

//读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写

public PropertiesSettings(String name){

URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

settings.getImpl(name),if(settingsUrl == null){

LOG.debug(name + “.properties missing”);

settings = new LocatableProperties();

return;

}

settings

// Load settings

InputStream in = null;

try {

in = settingsUrl.openStream();

settings.load(in);

} catch(IOException e){

throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

} finally {

if(in!= null){

try {

in.close();

} catch(IOException io){

LOG.warn(“Unable to close input stream”, io);

}

}

}

}

//loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props

//这个props是register的一个入参.protected void loadSettings(LocatableProperties props, final Settings settings){

// We are calling the impl methods to get around the single instance of Settings that is expected

for(Iterator i = settings.listImpl();i.hasNext();){

String name =(String)i.next();

=

new

LocatableProperties(new

LocationImpl(null, settingsUrl.toString()));

props.setProperty(name, settings.getLocationImpl(name));

}

}

再来看第二步:init_TraditionalXmlConfigurations()

private void init_TraditionalXmlConfigurations(){

//首先读取web.xml中的config初始参数值

//如果

使

settings.getImpl(name),用默认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

private void init_TraditionalXmlConfigurations(){

//首先读取web.xml中的config初始参数值

//如果

使

认的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//这儿就可以看出为什么默认的配置文件必须取名为这三个名称了

//如果不想使用默认的名称,直接在web.xml中配置config初始参数即可

String configPaths = initParams.get(“config”);

if(configPaths == null){

configPaths = DEFAULT_CONFIGURATION_PATHS;

}

String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

for(String file : files){

if(file.endsWith(“.xml”)){

if(“xwork.xml”.equals(file)){

//XmlConfigurationProvider负责解析xwork.xml

configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

} else {

//其它xml都是由StrutsXmlConfigurationProvider来解析

configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

}

} else {

throw new IllegalArgumentException(“Invalid configuration file name”);

}

}

}

对于其它配置文件只用接口。

类XmlConfigurationProvider负责配置文件的读取和解析,首先通过init()中的loadDocuments(configFileName);利用DomHelper中的

public static Document parse(InputSource inputSource, Map dtdMappings)将configFileName配置文件通过SAX解析方式按照DtdMappings解析成StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProviderDocument对象.然后通过Provider的register()方法加载“bean”和“constant”属性,再通过loadPackages()加载package及package中的属性

addAction()方法负责读取标签,并将数据保存在ActionConfig中; addResultTypes()方法负责将标签转化为ResultTypeConfig对象; loadInterceptors()方法负责将标签转化为InterceptorConfi对象;

loadInterceptorStack()方法负责将标签转化为InterceptorStackConfig对象;

loadInterceptorStacks()方法负责将标签转化成InterceptorStackConfig对象。

而上面的方法最终会被addPackage()方法调用,addPackage又会被Provider的loadPackages()调用,将所读取到的数据汇集到PackageConfig对象中。

protected PackageConfig

addPackage(Element

packageElement)

throws ConfigurationException {

PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if(newPackage.isNeedsRefresh()){

return newPackage.build();

}

// add result types(and default result)to this package

addResultTypes(newPackage, packageElement);

// load the interceptors and interceptor stacks for this package

loadInterceptors(newPackage, packageElement);

// load the default interceptor reference for this package

loadDefaultInterceptorRef(newPackage, packageElement);

// load the default class ref for this package

loadDefaultClassRef(newPackage, packageElement);

// load the global result list for this package

loadGlobalResults(newPackage, packageElement);

// load the global exception handler list for this package

loadGobalExceptionMappings(newPackage, packageElement);

// get actions

NodeList actionList = packageElement.getElementsByTagName(“action”);

for(int i = 0;i < actionList.getLength();i++){

Element actionElement =(Element)actionList.item(i);

addAction(actionElement, newPackage);

}

// load the default action reference for this package

loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();

configuration.addPackageConfig(cfg.getName(), cfg);

return cfg;

}

loadConfigurationFiles解析读取xml中的内容

private List

loadConfigurationFiles(String

fileName, includeElement){

...//通过DomHelper调用SAX进行解析xml

doc = DomHelper.parse(in, dtdMappings);

...Element rootElement = doc.getDocumentElement();

NodeList children = rootElement.getChildNodes();

int childSize = children.getLength();

for(int i = 0;i < childSize;i++){

Node childNode = children.item(i);

if(childNode instanceof Element){

Element child =(Element)childNode;

final String nodeName = child.getNodeName();

if(“include”.equals(nodeName)){

String includeFileName = child.getAttribute(“file”);

//解析每个action配置是,对于include文件可以使用通配符*来进行配置

//如Struts.xml中可配置成

if(includeFileName.indexOf('*')!=-1){

ClassPathFinder wildcardFinder = new ClassPathFinder();

wildcardFinder.setPattern(includeFileName);

Element

Vector wildcardMatches = wildcardFinder.findMatches();

for(String match : wildcardMatches){

//递归Load子file中的

docs.addAll(loadConfigurationFiles(match, child));

}

} else {

docs.addAll(loadConfigurationFiles(includeFileName, child));

}

}

}

}

docs.add(doc);

loadedFileUrls.add(url.toString());

...return docs;

}

接下来第三步:init_LegacyStrutsProperties()调用的是调用的是LegacyPropertiesConfigurationProvider 通过比较前

DefaultPropertiesProvider

用的是LegacyPropertiesConfigurationProvider.发现DefaultPropertiesProvider继承自后者,但重写了register()方法,主要是生成PropertiesSetting的不同,前者是根据org/apache/struts2/default.properties 后者是根据struts.properties 我们展开register()中的Settings.getInstance(),最后是调用getDefaultInstance()

private static Settings getDefaultInstance(){

if(defaultImpl == null){

// Create bootstrap implementation

//不带参数的DefaultSettings(),区别与DefaultPropertiesProvider中直接带default.properties参数

//不带参数就是默认为struts.propertes,并且加载struts.custom.properties所定义的properties文件

defaultImpl = new DefaultSettings();

// Create default implementation

try {

//STRUTS_CONFIGURATION为:struts.configuration

//在struts.proterties中查找struts.configuration的值,这个值必须是org.apache.struts2.config.Configuration接口的实现类

//所以我有个困惑就是在下面的转换当中怎么将Configuration转换成Setting类型的...//这一点先放下了,有时间再研究

String className = get(StrutsConstants.STRUTS_CONFIGURATION);

if(!className.equals(defaultImpl.getClass().getName())){

try {

// singleton instances shouldn't be built accessing request or session-specific context data

defaultImpl oader().loadClass(className), null);

} catch(Exception e){

LOG.error(“Settings:

}

}

} catch(IllegalArgumentException ex){

// ignore

}

private static Settings getDefaultInstance(){

if(defaultImpl == null){

// Create bootstrap implementation

//不带参数的DefaultSettings(),区别与DefaultPropertiesProvider中直接带default.properties参数

//不带参数就是默认为struts.propertes,并且加载struts.custom.properties所定义的properties文件

defaultImpl = new DefaultSettings();

// Create default implementation

try {

//STRUTS_CONFIGURATION为:struts.configuration

//在struts.proterties中查找struts.configuration的值,这个值必须是

Could

not

instantiate

the struts.configuration object, substituting the default implementation.”, e);

=

(Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLorg.apache.struts2.config.Configuration接口的实现类

//所以我有个困惑就是在下面的转换当中怎么将Configuration转换成Setting类型的...//这一点先放下了,有时间再研究

String className = get(StrutsConstants.STRUTS_CONFIGURATION);

if(!className.equals(defaultImpl.getClass().getName())){

try {

// singleton instances shouldn't be built accessing request or session-specific context data

defaultImpl oader().loadClass(className), null);

} catch(Exception e){

LOG.error(“Settings:

}

}

} catch(IllegalArgumentException ex){

// ignore

}

在2.1.6中去掉了第四步:init_ZeroConfiguration();第五步是自定义的configProviders

private void init_CustomConfigurationProviders(){

//从这里可以看到可以将自定义的Provider定义在web.xml中FilterDispatcher的param中:configProviders

String configProvs = initParams.get(”configProviders“);

if(configProvs!= null){

String[] classes = configProvs.split(”¥¥s*[,]¥¥s*“);

for(String cname : classes){

try {

Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

ConfigurationProvider(ConfigurationProvider)cls.newInstance();

configurationManager.addConfigurationProvider(prov);

prov

=

Could

not

instantiate

the struts.configuration object, substituting the default implementation.”, e);

=

(Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassL

}

...}

}

}

private void init_CustomConfigurationProviders(){

//从这里可以看到可以将自定义的Provider定义在web.xml中FilterDispatcher的param中:configProviders

String configProvs = initParams.get(“configProviders”);

if(configProvs!= null){

String[] classes = configProvs.split(“¥¥s*[,]¥¥s*”);

for(String cname : classes){

try {

Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

ConfigurationProvider(ConfigurationProvider)cls.newInstance();

configurationManager.addConfigurationProvider(prov);

}

...}

}

}

第六步:init_FilterInitParameters

//从这里可以看出struts.properties中的属性不仅可以在struts.xml中以constant形式定义,而且可以在FilterDispatcher的param中定义

private void init_FilterInitParameters(){

configurationManager.addConfigurationProvider(new ConfigurationProvider(){

public void destroy(){}

public

void

init(Configuration

configuration)

throws ConfigurationException {}

public void loadPackages()throws ConfigurationException {}

public boolean needsReload(){ return false;}

prov

=

public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

props.putAll(initParams);//在这里实现滴~

}

});

}

//从这里可以看出struts.properties中的属性不仅可以在struts.xml中以constant形式定义,而且可以在FilterDispatcher的param中定义

private void init_FilterInitParameters(){

configurationManager.addConfigurationProvider(new ConfigurationProvider(){

public void destroy(){}

public

void

init(Configuration

configuration)

throws ConfigurationException {}

public void loadPackages()throws ConfigurationException {}

public boolean needsReload(){ return false;}

public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

props.putAll(initParams);//在这里实现滴~

}

});

}

第七步:init_AliasStandardObjects,使用BeanSelectionProvider 这是将配置文件中定义的与实际的类相映射,就是注入bean的依赖关系,这部分以后有时候再研究Container

接下来是看怎样调用这些ConfigurationProviders 展开init_PreloadConfiguration()

private Container init_PreloadConfiguration(){

Configuration config = configurationManager.getConfiguration();

Container container = config.getContainer();

boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

LocalizedTextUtil.setReloadBundles(reloadi18n);

return container;

}

//再看getConfiguration()

public synchronized Configuration getConfiguration(){

if(configuration == null){

setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

try {

//重点就是这个reloadContainer

configuration.reloadContainer(getContainerProviders());

} catch(ConfigurationException e){

setConfiguration(null);

throw new ConfigurationException(“Unable to load configuration.”, e);

}

} else {

conditionalReload();

}

return configuration;

}

private Container init_PreloadConfiguration(){

Configuration config = configurationManager.getConfiguration();

Container container = config.getContainer();

boolean reloadi18n

=

Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

LocalizedTextUtil.setReloadBundles(reloadi18n);

return container;

}

//再看getConfiguration()

public synchronized Configuration getConfiguration(){

if(configuration == null){

setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

try {

//重点就是这个reloadContainer

configuration.reloadContainer(getContainerProviders());

} catch(ConfigurationException e){

setConfiguration(null);

throw new ConfigurationException(“Unable to load configuration.”, e);

}

} else {

conditionalReload();

}

return configuration;

}

展开DefaultConfiguration中的reloadContainer

public synchronized List

reloadContainer(List providers)throws ConfigurationException {

packageContexts.clear();

loadedFileNames.clear();

List

packageProviders = new ArrayList

();

//Struts2(xwork2)用Container来完成依赖注入的功能

//首先初始化一个ContainerBuilder,再由builder来保存接口与实现类或工厂类的对应关系

//然后通过builder.create(boolean)方法产生container

//由container.getInstance(Class);就可以得到接口的实现实例了

//这一部分比较复杂,后面研究完成了,会单独拿出来讲,这里先弄清楚Xwork依赖注入的实现步骤就可以了

ContainerProperties props = new ContainerProperties();

ContainerBuilder builder = new ContainerBuilder();

for(final ContainerProvider containerProvider : providers)

{

//循环调用ConfigurationProvider的init和register方法,明白了吧,在这里统一循环调用

containerProvider.init(this);

containerProvider.register(builder, props);

}

props.setConstants(builder);

//注入依赖关系,在这里并不产生实例

builder.factory(Configuration.class, new Factory(){

public Configuration create(Context context)throws Exception {

return DefaultConfiguration.this;

}

});

ActionContext oldContext = ActionContext.getContext();

try {

// Set the bootstrap container for the purposes of factory creation

Container bootstrap = createBootstrapContainer();

setContext(bootstrap);

//create已经注入依赖关系的Container

container = builder.create(false);

setContext(container);

objectFactory = container.getInstance(ObjectFactory.class);

// Process the configuration providers first

for(final ContainerProvider containerProvider : providers)

{

if(containerProvider instanceof PackageProvider){

container.inject(containerProvider);

//调用PackageProvider的loadPackages()方法,这里主要是针对XmlConfigurationProvider和StrutsXmlConfigurationProvider

((PackageProvider)containerProvider).loadPackages();

packageProviders.add((PackageProvider)containerProvider);

}

}

// Then process any package providers from the plugins

Set

packageProviderNames

= container.getInstanceNames(PackageProvider.class);

if(packageProviderNames!= null){

for(String name : packageProviderNames){

PackageProvider

provider.init(this);

provider.loadPackages();

packageProviders.add(provider);

}

}

rebuildRuntimeConfiguration();

} finally {

if(oldContext == null){

ActionContext.setContext(null);

}

}

return packageProviders;

}

Dispatcher已经在之前讲过,这就好办了。FilterDispatcher是Struts2的核心控制器,首先看一下init()方法。

public void init(FilterConfig filterConfig)throws ServletException {

try {

this.filterConfig = filterConfig;

initLogging();

//创建dispatcher,前面都已经讲过啰

dispatcher = createDispatcher(filterConfig);

dispatcher.init();

//注入将FilterDispatcher中的变量通过container注入,如下面的staticResourceLoader

dispatcher.getContainer().inject(this);

//StaticContentLoader在BeanSelectionProvider中已经被注入了依赖关系:DefaultStaticContentLoader

//可以在struts-default.xml中的可以找到

staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

} finally {

provider

= container.getInstance(PackageProvider.class, name);

ActionContext.setContext(null);

}

}

public void init(FilterConfig filterConfig)throws ServletException {

try {

this.filterConfig = filterConfig;

initLogging();

//创建dispatcher,前面都已经讲过啰

dispatcher = createDispatcher(filterConfig);

dispatcher.init();

//注入将FilterDispatcher中的变量通过container注入,如下面的staticResourceLoader

dispatcher.getContainer().inject(this);

//StaticContentLoader在BeanSelectionProvider中已经被注入了依赖关系:DefaultStaticContentLoader

//可以在struts-default.xml中的可以找到

staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

} finally {

ActionContext.setContext(null);

}

}

//下面来看DefaultStaticContentLoader的setHostConfig

public void setHostConfig(HostConfig filterConfig){

//读取初始参数

pakages,调用

parse(),解析成类似/org/apache/struts2/static,/template的数组

String param = filterConfig.getInitParameter(“packages”);

//“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

String packages = getAdditionalPackages();

if(param!= null){

packages = param + “ ” + packages;

}

this.pathPrefixes = parse(packages);

initLogging(filterConfig);

}

template //下面来看DefaultStaticContentLoader的setHostConfig

public void setHostConfig(HostConfig filterConfig){

//读取初始参数

pakages,调用

parse(),解析成类似/org/apache/struts2/static,/template的数组

String param = filterConfig.getInitParameter(“packages”);

//“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

String packages = getAdditionalPackages();

if(param!= null){

packages = param + “ ” + packages;

}

this.pathPrefixes = parse(packages);

initLogging(filterConfig);

}

现在回去doFilter的方法,每当有一个Request,都会调用这些Filters的doFilter方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

HttpServletRequest request =(HttpServletRequest)req;

HttpServletResponse response =(HttpServletResponse)res;

ServletContext servletContext = getServletContext();

String timerKey = “FilterDispatcher_doFilter: ”;

try {

// FIXME: this should be refactored better to not duplicate work with the action invocation

//先看看ValueStackFactory所注入的实现类OgnlValueStackFactory

//new OgnlValueStack

ValueStack

stack

= dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

ActionContext ctx = new ActionContext(stack.getContext());

ActionContext.setContext(ctx);

template

UtilTimerStack.push(timerKey);

//如果是multipart/form-data就用MultiPartRequestWrapper进行包装

//MultiPartRequestWrapper

StrutsRequestWrapper的子类,两者都是HttpServletRequest实现

//此时在MultiPartRequestWrapper中就会把Files给解析出来,用于文件上传

//所有request都会StrutsRequestWrapper进行包装,StrutsRequestWrapper是可以访问ValueStack

//下面是参见Dispatcher的wrapRequest

// String content_type = request.getContentType();

//if(content_type!= null&&content_type.indexOf(“multipart/form-data”)!=-1){

//MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

//request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

//} else {

//

request = new StrutsRequestWrapper(request);

// }

request = prepareDispatcherAndWrapRequest(request, response);

ActionMapping mapping;

try {

//根据url取得对应的Action的配置信息

//看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存储在 ActionMapping对象中

mapping

=

actionMapper.getMapping(request, dispatcher.getConfigurationManager());

} catch(Exception ex){

log.error(“error getting ActionMapping”, ex);

dispatcher.sendError(request,return;

}

//如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等

//这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到

response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

=new 404

if(mapping == null){

// there is no action in this request, should we look for a static resource?

String resourcePath = RequestUtils.getServletPath(request);

if(“".equals(resourcePath)&& null!= request.getPathInfo()){

resourcePath = request.getPathInfo();

}

if(staticResourceLoader.canHandle(resourcePath)){

// 在DefaultStaticContentLoader

:return

serveStatic

&&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

staticResourceLoader.findStaticResource(resourcePath, response);

} else {

// this is a normal request, let it pass through

chain.doFilter(request, response);

}

// The framework did its job here

return;

}

//正式开始Action的方法

dispatcher.serviceAction(request, response, servletContext, mapping);

} finally {

try {

ActionContextCleanUp.cleanUp(req);

} finally {

UtilTimerStack.pop(timerKey);

}

}

}

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

HttpServletRequest request =(HttpServletRequest)req;

request,HttpServletResponse response =(HttpServletResponse)res;

ServletContext servletContext = getServletContext();

String timerKey = ”FilterDispatcher_doFilter: “;

try {

// FIXME: this should be refactored better to not duplicate work with the action invocation

//先看看ValueStackFactory所注入的实现类OgnlValueStackFactory

//new OgnlValueStack

ValueStack

stack

= dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

ActionContext ctx = new ActionContext(stack.getContext());

ActionContext.setContext(ctx);

UtilTimerStack.push(timerKey);

//如果是multipart/form-data就用MultiPartRequestWrapper进行包装

//MultiPartRequestWrapperHttpServletRequest实现

//此时在MultiPartRequestWrapper中就会把Files给解析出来,用于文件上传

//所有request都会StrutsRequestWrapper进行包装,StrutsRequestWrapper是可以访问ValueStack

//下面是参见Dispatcher的wrapRequest

// String content_type = request.getContentType();

//if(content_type!= null&&content_type.indexOf(”multipart/form-data“)!=-1){

//MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

//request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

//} else {

//

request = new StrutsRequestWrapper(request);

// }

request = prepareDispatcherAndWrapRequest(request, response);

ActionMapping mapping;

try {

=new

StrutsRequestWrapper的子类,两者都是

//根据url取得对应的Action的配置信息

//看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存储在 ActionMapping对象中

mapping

} catch(Exception ex){

log.error(”error getting ActionMapping“, ex);

dispatcher.sendError(request,return;

}

//如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等

//这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404

if(mapping == null){

// there is no action in this request, should we look for a static resource?

String resourcePath = RequestUtils.getServletPath(request);

if(”“.equals(resourcePath)&& null!= request.getPathInfo()){

resourcePath = request.getPathInfo();

}

if(staticResourceLoader.canHandle(resourcePath)){

// 在DefaultStaticContentLoader

:return

serveStatic

&&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

staticResourceLoader.findStaticResource(resourcePath, response);

} else {

// this is a normal request, let it pass through

chain.doFilter(request, response);

}

// The framework did its job here

return;

}

request,response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

=

actionMapper.getMapping(request, dispatcher.getConfigurationManager());

//正式开始Action的方法

dispatcher.serviceAction(request, response, servletContext, mapping);

} finally {

try {

ActionContextCleanUp.cleanUp(req);

} finally {

UtilTimerStack.pop(timerKey);

}

}

}

//下面是ActionMapper接口的实现类 DefaultActionMapper的getMapping()方法的源代码:

public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

ActionMapping mapping = new ActionMapping();

String uri = getUri(request);//得到请求路径的URI,如:testAtcion.action或testAction.do

int indexOfSemicolon = uri.indexOf(”;“);//修正url的带;jsessionid 时找不到而且的bug

uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

uri = dropExtension(uri, mapping);//删除扩展名,默认扩展名为action

if(uri == null){

return null;

}

parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

handleSpecialParameters(request, mapping);//去掉重复参数

//如果Action的name没有解析出来,直接返回

if(mapping.getName()== null){

returnnull;

}

//下面处理形如testAction!method格式的请求路径

if(allowDynamicMethodCalls){

// handle ”name!method“ convention.String name = mapping.getName();

int exclamation = name.lastIndexOf(”!“);//!是Action名称和方法名的分隔符

if(exclamation!=-1){

mapping.setName(name.substring(0, exclamation));//提取左边为name

mapping.setMethod(name.substring(exclamation + 1));//提取右边的method

}

}

return mapping;

}

//下面是ActionMapper接口的实现类 DefaultActionMapper的getMapping()方法的源代码:

public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

ActionMapping mapping = new ActionMapping();

String uri = getUri(request);//得到请求路径的URI,如:testAtcion.action或testAction.do

int indexOfSemicolon = uri.indexOf(”;“);//修正url的带;jsessionid 时找不到而且的bug

uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

uri = dropExtension(uri, mapping);//删除扩展名,默认扩展名为action

if(uri == null){

return null;

}

parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

handleSpecialParameters(request, mapping);//去掉重复参数

//如果Action的name没有解析出来,直接返回

if(mapping.getName()== null){

returnnull;

}

//下面处理形如testAction!method格式的请求路径

if(allowDynamicMethodCalls){

// handle ”name!method“ convention.String name = mapping.getName();

int exclamation = name.lastIndexOf(”!“);//!是Action名称和方法名的分隔符

if(exclamation!=-1){

mapping.setName(name.substring(0, exclamation));//提取左边为name

mapping.setMethod(name.substring(exclamation + 1));//提取右边的method

}

}

return mapping;

}

从代码中看出,getMapping()方法返回ActionMapping类型的对象,该对象包含三个参数:Action的name、namespace和要调用的方法method。

如果getMapping()方法返回ActionMapping对象为null,则FilterDispatcher认为用户请求不是Action,自然另当别论,FilterDispatcher会做一件非常有意思的事:如果请求以/struts开头,会自动查找在web.xml文件中配置的 packages初始化参数,就像下面这样:

struts2

org.apache.struts2.dispatcher.FilterDispatcher

packages

com.lizanhong.action

struts2

org.apache.struts2.dispatcher.FilterDispatcher

packages

com.lizanhong.action

FilterDispatcher会将com.lizanhong.action包下的文件当作静态资源处理,即直接在页面上显示文件内容,不过会忽略扩展名为class的文件。比如在com.lizanhong.action包下有一个aaa.txt的文本文件,其内容为“中华人民共和国”,访问

http://localhost:8081/Struts2Demo/struts/aaa.txt时会输出txt中的内容

FilterDispatcher.findStaticResource()方法

protectedvoid findStaticResource(String

name,HttpServletRequest

request, HttpServletResponse response)throws IOException {

if(!name.endsWith(”.class“)){//忽略class文件

//遍历packages参数

for(String pathPrefix : pathPrefixes){

InputStream is = findInputStream(name, pathPrefix);//读取请求文件流

if(is!= null){

...// set the content-type header

String contentType = getContentType(name);//读取内容类型

if(contentType!= null){

response.setContentType(contentType);//重新设置内容类型

}

...try {

//将读取到的文件流以每次复制4096个字节的方式循环输出

copy(is, response.getOutputStream());

} finally {

is.close();

}

return;

}

}

}

}

protectedvoid findStaticResource(String

name,HttpServletRequest

request, HttpServletResponse response)throws IOException {

if(!name.endsWith(”.class“)){//忽略class文件

//遍历packages参数

for(String pathPrefix : pathPrefixes){

InputStream is = findInputStream(name, pathPrefix);//读取请求文件流

if(is!= null){

...// set the content-type header

String contentType = getContentType(name);//读取内容类型

if(contentType!= null){

response.setContentType(contentType);//重新设置内容类型

}

...try {

//将读取到的文件流以每次复制4096个字节的方式循环输出

copy(is, response.getOutputStream());

} finally {

is.close();

}

return;

}

}

}

}

如果用户请求的资源不是以/struts开头——可能是.jsp文件,也可能是.html文件,则通过过滤器链继续往下传送,直到到达请求的资源为止。

如果getMapping()方法返回有效的ActionMapping对象,则被认为正在请求某个Action,将调用 Dispatcher.serviceAction(request, response, servletContext, mapping)方法,该方法是处理Action的关键所在。

下面就来看serviceAction,这又回到全局变量dispatcher中了

//Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException {

//createContextMap方法主要把Application、Session、Request的key value值拷贝到Map中

Map extraContext = createContextMap(request, response, mapping, context);

// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action

ValueStack

stack

=

(ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

boolean nullStack = stack == null;

if(nullStack){

ActionContext ctx = ActionContext.getContext();

if(ctx!= null){

stack = ctx.getValueStack();

}

}

if(stack!= null){

extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));

}

String timerKey = ”Handling request from Dispatcher“;

try {

UtilTimerStack.push(timerKey);

String namespace = mapping.getNamespace();

String name = mapping.getName();

String method = mapping.getMethod();

Configuration config = configurationManager.getConfiguration();

//创建一个Action的代理对象,ActionProxyFactory是创建ActionProxy的工厂

//参考实现类:DefaultActionProxy和DefaultActionProxyFactory

ActionProxy

proxy

= config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext, true, false);

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

// if the ActionMapping says to go straight to a result, do it!

//如果是Result,则直接转向,关于Result,ActionProxy,ActionInvocation下一讲中再分析

if(mapping.getResult()!= null){

Result result = mapping.getResult();

result.execute(proxy.getInvocation());

} else {

//执行Action

proxy.execute();

}

// If there was a previous value stack then set it back onto the request

if(!nullStack){

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

}

} catch(ConfigurationException e){

// WW-2874 Only log error if in devMode

if(devMode){

LOG.error(”Could not find action or result“, e);

}

else {

LOG.warn(”Could not find action or result“, e);

}

sendError(request, HttpServletResponse.SC_NOT_FOUND, e);

} catch(Exception e){

sendError(request,} finally {

UtilTimerStack.pop(timerKey);

}

} 下面开始讲一下主菜ActionProxy了.在这之前最好先去了解一下动态Proxy的基本知识.ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。DefaultActionInvocation()->init()->createAction()。

最后

用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()这里的步骤是先由ActionProxyFactory创建ActionInvocation和ActionProxy.public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

container.inject(inv);

return }

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

response,context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);

response,context,ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

container.inject(inv);

return }

下面先看DefaultActionInvocation的init方法

public void init(ActionProxy proxy){

this.proxy = proxy;

Map contextMap = createContextMap();

// Setting this so that other classes, like object factories, can use the ActionProxy and other

// contextual information to operate

ActionContext actionContext = ActionContext.getContext();

if(actionContext!= null){

actionContext.setActionInvocation(this);

}

//创建Action,struts2中每一个Request都会创建一个新的Action

createAction(contextMap);

if(pushAction){

stack.push(action);

contextMap.put(”action“, action);

}

invocationContext = new ActionContext(contextMap);

invocationContext.setName(proxy.getActionName());

// get a new List so we don't get problems with the iterator if someone changes the list

List

interceptorList

=

new ArrayList(proxy.getConfig().getInterceptors());

interceptors = interceptorList.iterator();

createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

}

protected void createAction(Map contextMap){

// load action

String timerKey = ”actionCreate: “ + proxy.getActionName();

try {

UtilTimerStack.push(timerKey);

//默认为SpringObjectFactory:struts.objectFactory=spring.这里非常巧妙,在struts.properties中可以重写这个属性

//在前面BeanSelectionProvider中通过配置文件为ObjectFactory设置实现类

//这里以Spring为例,这里会调到SpringObjectFactory的buildBean方法,可以通过ApplicationContext的getBean()方法得到Spring的Bean

action

=

objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);

} catch(InstantiationException e){

throw new

XWorkException(”Unable

to

intantiate

Action!“,e, proxy.getConfig());

} catch(IllegalAccessException e){

throw new XWorkException(”Illegal access to constructor, is it public?", e, proxy.getConfig());

} catch(Exception e){

...} finally {

UtilTimerStack.pop(timerKey);

}

if(actionEventListener!= null){

action = actionEventListener.prepare(action, stack);

}

}

//SpringObjectFactory

public Object buildBean(String beanName, Map extraContext, boolean injectInternal)throws Exception {

Object o = null;

try {

//SpringObjectFactory

web.xml

中的

下载ssh框架的构成分析和代码构架小结word格式文档
下载ssh框架的构成分析和代码构架小结.doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    组织构架图实例分析

    组织构架图实例分析一, 公司简介1. 简史:联想集团成立于1984年,由中科院计算所投资20万元人民币、11名科技人员创办,是一家在信息产业内多元化发展的大型企业集团,富有创新性的国......

    平面构成课程小结

    平面设计是将不同的基本图形,按照一定的规则在平面上组合成图案的。主要在二度空间范围之内以轮廓线划分图与地之间的界限,描绘形象。而平面设计所表现的立体空间感,并非实在的......

    平面构成小结(最终版)

    平面构成小结.txt28生活是一位睿智的长者,生活是一位博学的老师,它常常春风化雨,润物无声地为我们指点迷津,给我们人生的启迪。不要吝惜自己的爱,敞开自己的胸怀,多多给予,你会发现......

    立体构成课程小结

    立体构成课程小结: 姓名:黎旭辉 班级:10级艺术设计(2)班 学号:1008022013 通过几周的立体构成的学习,让我更全面了解了一些关于立体构成的基础知识,总体上来讲立体构成这门课程研究......

    色彩构成小结[5篇材料]

    色彩构成小结 一个月的色彩构成课结束了,开始还是有些无存下手。不指导自己应该画什么,想什么。经过老师的理论知识讲课,我明白了关于色彩的很多东西。 首先我知道了色彩构成将......

    It构成的句型小结

    一、 It作形式主语的句型 为使句子平衡,往往把it置于句首作形式主语,而把真正的主语(通常是不定式短语、动名词短语或主语从句)移至句末。It 作形式主语的句型有: ㈠ it 代指不定......

    比较级构成及句型归纳小结

    形容词和副词比较级构成及用法归纳 1. 以形容词+ly 构成的副词,其比较级构成是在前面加more 例如:carefully – more carefully loudly – more loudly quietly – more quie......

    典型相关分析SAS代码

    data fit; input X1 X2 X3 X4 X5 Y1 Y2 Y3; cards; 14651000 3446 98.8 2094.51 104.2 2555.14 2637.67 179.76 13985000 3339 113.8 2305.2233 133.8 2462.45 2670.99 161.......