Struts1工作原理 
   1.系统初始化(读取配置):初始化ModuleConfig对象 
      Struts框架是一个总控制器(ActionServlet)是一个Servlet,在web.xml中配置成自动启动的Servlet。 
   读取配置文件的配置信息,为不同的struts模块初始化相应的ModuleConfig对象(ActionConfig、 
   ControlConfig、FormBeanConfig、ForwardConfig、MessageResponseConfig)。 
   
   2.发送请求 
   3.填充Form(实例化、复位、填充数据、校验):请求时ActionServlet为我们填充。如果有对应的FormBean实例化并填充http的请求数据,并保存在Servlet Context中(request或session),这样就可以被其他Action或jsp调用。 
   4.派发请求:控制器根据配置信息ActionConfig将请求派发给具体的Action,相应的FormBean一并派发。 
   5.处理业务:Action的execute。 
   6.返回响应:完毕后返回一个ActionForward对象。 
   7.查找响应(翻译响应):总控制器根据Action返回的目标响应对象,查找对应的资源对象。 
   8.响应用户:目标响应对象将结果展现给用户

工作流程: 
jsp请求,服务器servlet mapping(*.do),前端控制器(ActionServlet)响应,封装FormBean,派发请求,Action execute,完毕后返回一个ActionForward对象,查找响应,响应用户


自己用Struts 写一个登入项目

类: LoginAction(继承action)

LoginActionForm(继承ActionForm)

manager(设计成单例 里面写具体的login方法)

jsp:login (写个表单)

success

erro

写完之后 配置struts-config.xml 和 web.xml 如下:

<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans>
<form-bean
name="LoginActionForm"
type="com.LoginActionForm"/>

</form-beans>
<action-mappings>
<action
name="LoginActionForm" path="/login"
scope="request"
type="com.LoginAction"
validate="true" >
<forward name="success" path="/loginsuccess.jsp"/>
<forward name="erro" path="/loginerro.jsp"/>
</action>
</action-mappings>
</struts-config>
/* 令人蛋痛的 Struts配置 第一行 一定是<? xml ?> 。 还有<!DOCTYPE>,一些拼写错写 以及 ">","/>"的问题要小心 */


接下来就是源码部分一个一个按照上面写的流程来看

/*

这个就是初始化

*/

ModuleConfig

实现代码:

public ModuleConfigImpl(String prefix) {

super();

this.prefix = prefix;

this.actionConfigs = new HashMap();

this.actionConfigList = new ArrayList();

this.actionFormBeanClass = "org.apache.struts.action.ActionFormBean";

this.actionMappingClass = "org.apache.struts.action.ActionMapping";

this.actionForwardClass = "org.apache.struts.action.ActionForward";

this.configured = false;

this.controllerConfig = null;

this.dataSources = new HashMap();

this.exceptions = new HashMap();

this.formBeans = new HashMap();

this.forwards = new HashMap();

this.messageResources = new HashMap();

this.plugIns = new ArrayList();

}

/*

用户发送请求

*/

http://127.0.0.1:8080/struts_login/login.do

/*

解析http的内容  将path 封装成对象 读取struts-config xml

* /

1、 String path = processPath(request, response);

实现代码:

path = request.getServletPath();

path =="/login.do"

int slash = path.lastIndexOf("/");

int period = path.lastIndexOf(".");

if ((period >= 0) && (period > slash)) {

path = path.substring(0, period);

}

return (path);

path="/login"

2、ActionMapping mapping = processMapping(request, response, path);

实现代码:

ActionMapping mapping = (ActionMapping)

moduleConfig.findActionConfig(path);

从ActionConfigs的MAP中通过path取得对应的ActionMapping对象

<action-mappings>

<action path="/login"

type="com.struts.LoginAction"

name="loginForm"

scope="request"

validate="true"

>

<forward name="success" path="/login_success.jsp"/>

<forward name="error" path="/login_error.jsp"/>

</action>

</action-mappings>

在一个web 项目中,每个资源都必须用URL来引用,资源包括:jsp,html,和制定动作。为了给制定动作一个URL,Struts提供了一个ActionMapping对象

(在Struts中,ActionMapping继承自ActionConfig,大部份的属性定义实际上都已经在ActionConfig中完成,不过ActionMapping仍旧存在)。

当请求的URL是:http://127.0.0.1:8080/struts_login/login.do,则ActionServlet会将path设定为/login,

然后会根据 /login, 找到xml里的配置信息并读取 ,找到Actionmapping  对象。该ActionMapping对象告知ActionServlet要使用“com.struts.LoginAction”,

而后ActionServlet会将呼叫LoginAction的execute()方法,并将ActionMapping对象当作参数传递给它。

并接下来会根据 name=“loginForm”执行如下

Ps:(ActionServlet实际上将工作交给Action对象,然而Action对象的运作必须提供一些参数来描述工作的细节,诸如使用哪一个ActionForm、forward对象的查找、错误发生时的页面对象等等,Struts将这些信息包装在ActionMapping中,并作为参数传送给Action对象,以使得Action在需要相关的信息时可以从ActionMapping中取得。 )

---------------------------------------------------------------------------

3、ActionForm form = processActionForm(request, response, mapping);

实现代码:

ActionForm instance = RequestUtils.createActionForm()//创建ActionForm

if ("request".equals(mapping.getScope())) {

request.setAttribute(mapping.getAttribute(), instance);

} else {

HttpSession session = request.getSession();

session.setAttribute(mapping.getAttribute(), instance);

}

return (instance);

------------------------------

1)public static ActionForm createActionForm()

实现代码:

String attribute = mapping.getAttribute();

if (attribute == null) {

return (null);

}

String name = mapping.getName();

//从<formbeans>中通过name取得对应的FormBeanConfig对象

FormBeanConfig config = moduleConfig.findFormBeanConfig(name);

if (config == null) {

return (null);

// 从Scope中取得ActionForm

2)ActionForm instance = lookupActionForm(request, attribute,

mapping.getScope());

实现代码:

{if ("request".equals(scope)) {

instance = (ActionForm) request.getAttribute(attribute);

} else {

session = request.getSession();

instance = (ActionForm) session.getAttribute(attribute);

}

return (instance);}

if (instance != null && canReuseActionForm(instance, config)) {

return (instance);

}

return createActionForm(config, servlet);//反射方式生成ActionForm对象

可以看出创建ActionForm是通过单例模式来实现的。通过name=“LoginForm”,创建表单 "com.LoginActionForm"

----------------------------------------------------------------------------

/*

填充表单

*/

4、 processPopulate(request, response, form, mapping);

实现代码:

if (form == null) {

return;

}

form.reset(mapping, request);//ActionForm初始化

//ActionForm对象自动收集请求参数

RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix()

request);

---------------------

public static void populate()//自动收集请求参数

实现代码:

HashMap properties = new HashMap();

Enumeration names = null;

names = request.getParameterNames();

while (names.hasMoreElements()) {

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

String stripped = name;

Object parameterValue = null;

parameterValue = request.getParameterValues(name);

properties.put(stripped, parameterValue);

BeanUtils.populate(bean, properties);

----------------

public static void populate(Object bean, Map properties)

实现代码:

if ((bean == null) || (properties == null)) {

return;

Iterator names = properties.keySet().iterator();//取得参数名

while (names.hasNext()) {

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

Object value = properties.get(name);

setProperty(bean, name, value);

}

//对ActionForm信息进行验证

if (!processValidate(request, response, form, mapping)) {

return;

}

调用 processPopulate(request, response, form, mapping),将request里面的表单数据自动收集。

-----------------------------------------------------------------------------

//创建action对象

protected HashMap actions = new HashMap(); //

5、Action action = processActionCreate(request, response, mapping);

代码实现:

protected Action processActionCreate(HttpServletRequest request,

HttpServletResponse response,

ActionMapping mapping)

{String className = mapping.getType();

Action instance = null;

synchronized (actions) {

instance = (Action) actions.get(className);

if (instance != null) {

return (instance);

}

instance = (Action) RequestUtils.applicationInstance(className);

actions.put(className, instance);

return (instance);

}

action是通过单例加同步创建,高效安全。

并且在一个xml里面一个action标签对应一个action,一般有多个action标签

将这些action 存到hashmap  actions 如上 。

-----------------------------------------------------------------------------

//执行Action

6、ActionForward forward=

processActionPerform(request, response,action, form, mapping);

----------------------

代码实现:

protected ActionForward

processActionPerform(HttpServletRequest request,

HttpServletResponse response,

Action action,

ActionForm form,

ActionMapping mapping)

throws IOException, ServletException {

try {

return (action.execute(mapping, form, request, response));

} catch (Exception e) {

return (processException(request, response,

e, form, mapping));

}

}

执行action的   Actionforward execute(request,response,mapping,form) 返回一个  Actionforward

----------------------------------------------------------------------------

7、processForwardConfig(request, response, forward);

-------------------

代码实现:

protected void processForwardConfig(HttpServletRequest request,

HttpServletResponse response,

ForwardConfig forward)

throws IOException, ServletException {

if (forward == null) {

return;

}

String forwardPath = forward.getPath();

uri = forwardPath;

if (forward.getRedirect()) {

response.sendRedirect(response.encodeRedirectURL(uri));

else {

doForward(uri, request, response);

}

代码实现:

protected void doForward(

String uri,

HttpServletRequest request,

HttpServletResponse response)

throws IOException, ServletException

{RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);

rd.forward(request, response);

根据在xml action 标签 里的  forward的标签将跳转 ,整个登入结束。

ps:如果没有在xml配置mapping 则会返回一个null。

-----------------------------

Struts1 部分源码学习的更多相关文章

  1. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  2. jQuery源码学习感想

    还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...

  3. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

  4. MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

    前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...

  5. MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)

    前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...

  6. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

  7. 我的angularjs源码学习之旅2——依赖注入

    依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...

  8. ddms(基于 Express 的表单管理系统)源码学习

    ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...

  9. leveldb源码学习系列

    楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...

随机推荐

  1. 进程的基础理论、并发(multiprocessing模块)

    一.粘包优化方案 之前我们解决粘包的方式是用struct模块来制作一个报头,但是这个解决的方案是有漏洞的,当我们需要传送的文件大于2g时将会报错.所以我们今天将用json来制作报头. from soc ...

  2. JS 获取 今日、昨日、本周、本月、本季度、本年、上月、上周、上季度、去年

    /** * 日期范围工具类 */ var dateRangeUtil = (function () { /*** * 获得当前时间 */ this.getCurrentDate = function ...

  3. jQuery知识重构

    jQuery知识重构 目录: 一.入口函数 1          $(document).ready(function(){}); 2          $(function(){}); jQuery ...

  4. PHP函数:mysql_fetch_assoc指针重置

    本文目前主要讨论mysql_fetch_assoc“指针”如何重置的问题 要了解mysql_fetch_assoc,先看看它与mysql_fetch_row和mysql_fetch_array的关系. ...

  5. Graylog+elasticsearch+mongodb集群+nginx负载均衡前端

    网上有张图画的很好,搜索有关它的配置文章,google里有几篇英文的,都是依靠haproxy等或别的什么实现,没有纯粹的Graylog+elasticsearch+mongodb集群,项目需要,只有自 ...

  6. Python风格规范-FYI

    Python风格规范 分号 Tip 不要在行尾加分号, 也不要用分号将两条命令放在同一行. 行长度 Tip 每行不超过80个字符 例外: 长的导入模块语句 注释里的URL 不要使用反斜杠连接行. Py ...

  7. Android(java)学习笔记99:Java虚拟机和Dalvik虚拟机的区别

    Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野.它对内存的高效使用,和在低速CPU上表现出的高性能,确实令 ...

  8. python_52_函数返回值2

    def test1(x,y): print(x,y) test1(1,2)#位置参数调用,按顺序来,与形参一一对应 test1(y=1,x=2)#输出为2 1,不是1 2.关键字参数调用按关键字,不按 ...

  9. TensorFlow 内置重要函数解析

    概要 本部分介绍一些在 TensorFlow 中内置的重要函数,了解这些函数有时候更加方便我们进行数据的处理或者构建神经网络. 这些函数如下:       tf.one_hot()     tf.ra ...

  10. oc数组遍历

    #import <Foundation/Foundation.h> //数组遍历(枚举)对集合中的元素依此不重复的进行遍历 int main(int argc, const char * ...