Struts1 部分源码学习
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 部分源码学习的更多相关文章
- Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结
2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...
- jQuery源码学习感想
还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码, ...
- MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)
前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...
- MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)
前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...
- MVC系列——MVC源码学习:打造自己的MVC框架(二:附源码)
前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥.今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个 ...
- MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)
前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...
- 我的angularjs源码学习之旅2——依赖注入
依赖注入起源于实现控制反转的典型框架Spring框架,用来削减计算机程序的耦合问题.简单来说,在定义方法的时候,方法所依赖的对象就被隐性的注入到该方法中,在方法中可以直接使用,而不需要在执行该函数的时 ...
- ddms(基于 Express 的表单管理系统)源码学习
ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...
- leveldb源码学习系列
楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...
随机推荐
- Oracle Form个性化案例(一)
业务场景: 现有Form A,需通过A中的菜单栏中调用另一Form B,需将某值作为参数传入Form B中:
- DBA的做法
防止有人删除数据库,创建一个触发器当数据库被删除是发送一份邮件给管理员并撤销这个命令. Create trigger [tridbsafe]ON ALL SERVERFOR DROP_DATABASE ...
- 如何使用cPanel管理域名和数据库
cPanel是一个基于web的基于web的控制面板,它简化了许多常见的系统管理任务,如网站创建.数据库部署和管理等.本指南向您展示了如何使用cPanel用户帐户管理域和数据库.所有这些指令都与位于端口 ...
- cms-帖子幻灯图片上传
package com.open1111.controller.admin; import java.io.File;import java.util.Date;import java.util.Ha ...
- java Vamei快速教程13 String类
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 之前的Java基础系列中讨论了Java最核心的概念,特别是面向对象的基础.在Jav ...
- 流媒体 6——MPEG电视
1.电视图像的数据率 1.1 ITU-R BT.601标准数据率 按照奈奎斯特(Nyquist)采样理论,模拟电视信号经过采样(把连续的时间信号变成离散的时间信号)和量化 (把连续的幅度变成离散的幅度 ...
- Bezier贝塞尔曲线的原理、二次贝塞尔曲线的实现
Bezier曲线的原理 Bezier曲线是应用于二维图形的曲线.曲线由顶点和控制点组成,通过改变控制点坐标可以改变曲线的形状. 一次Bezier曲线公式: 一次Bezier曲线是由P0至P1的连续点, ...
- Java后台调用gcc编译C语言代码
想做一个能够在线编译代码运行的平台,Java和SQL已经支持了,因为是用Java写的后台,所以Java和SQL挺容易就实现了,做到支持C的时候就卡住了,网上搜了一下这种帖子好像很少. 我采取的办法是就 ...
- 问题 B: Curriculum Vitae
问题 B: Curriculum Vitae 时间限制: 1 Sec 内存限制: 128 MB提交: 109 解决: 25[提交][状态][讨论版][命题人:acm4302] 题目描述 Hideo ...
- MRCA|Wright–Fisher population genetic model|SNP rate
(Panda has a high heterozygosity rate) 通过对mtDNA(为了预测SNP的密度)的分析,可知panda的多样性,当前全基因组数据才能完全建立模型. mitocho ...