从源码分析struts框架执行流程

struts 源码解析
ActionServlet 的执行流程
•Tomcat 及封装配置
2 // web.xml 文件的 标签,配置则服务器启动则创建ActionServlet,否则访问时创建
Tomcat 一启动就将 web.xml 文件读取到内存,读取 标签创建出中央控制器 ActionServlet ,再将主配文件 struts-config.xml 读取到内存,实际是读取到内存的一个文件
对象 ModuleConfigImpl 中进行管理 – 将主配文件封装到 ModuleConfigImpl 文件对象中。

•ModuleConfigImpl() // 此对象继续封装配置信息

public ModuleConfigImpl( String prefix) { this.actionConfigs = new HashMap(); this.formBeans = new HashMap(); }

ModuleConfigImpl 对象创建 actionConfigs 和 formBeans 两个 Map 集合:
□actionConfigs:存放 ActionMapping 对象 – key 为 path,value 为
ActionMapping 对象

□ActionMapping 对象 – 封装对应的 标签中的各个属性
有几个 就有几个 ActionMapping 对象
ActionMapping 由 actionConfigs 来管理,数据结构为 Bean
□formBeans:存放 FormBeanConfig 对象 – key 为 name,value 为 FormBeanConfig 对象
□FormBeanConfig 对象 – 封装 标签里的 name 和type 属性

•ActionServlet.class
public class ActionServlet extends HttpServlet { // 中央控制器 struts 继承 HttpServlet 类,故有 init() / doGet() / doPost() / destroy() 方法protected String config = “/WEB-INF/struts-config.xml”; // 默认 config 就是 struts-config.xml

public void doGet( HttpServletRequest request, HttpServletResponse response)
		 throws IOException, ServletException { 
		 		process( request, response );
		 	 }

•process( request, response )

protected void process( HttpServletRequest request, HttpServletResponse response) 		
				throws IOException, ServletException {
				getRequestProcessor(getModuleConfig(request)).process(request, response); }

•process( request, response )

public void process( HttpServletRequest request, HttpServletResponse response)
			 throws IOException, ServletException { 截取 URL
			String path = processPath(request, response); 取得 ActionMapping
			ActionMapping mapping = processMapping(request, response, path);

创建 ActionForm
ActionForm form = processActionForm(request, response, mapping);
收集数据到 ActionForm
processPopulate(request, response, form, mapping);
// 收集完表单数据后,如果配置了 validate,就对表单数据中的格式做验证
if (!processValidate(request, response, form, mapping)) { return; }

实例化 Action
Action action = processActionCreate(request, response, mapping);
执行 Action 中的 execute() 方法
ActionForward forward = processActionPerform( request, response, action, form, mapping);
转向
processForwardConfig(request, response, forward); }

截取 URL
•processPath( request, response)
/* Tomcat 将请求字符串放在 request 内置对象中,此方法中获取请求字符串并截取所需字符 */
protected String processPath( HttpServletRequest request, HttpServletResponse response) throws IOException {
□请求字符串:http://127.0.0.1:8080/struts_login/login.do?username=“admin”&password=“admin”
path = request.getServletPath(); // 从项目名之后开始截取到最后,截取出 /login.do?username=“admin”&password=“admin”
int slash = path.lastIndexOf("/"); // 找子串最后一次出现的位置,得到 slash = 0
int period = path.lastIndexOf("."); // 得到 period = 6
if ((period >= 0) && (period > slash)) { path = path.substring(0, period); } // 截取出子串 path = “/login” return (path); } // 将截取出的子串 “/login” 返回给调用方法 process()

○子串截取:
□request.getURL(); // 从项目名开始到结束
□request.getServletPath(); // 从项目名之后开始截取到结束
□request.getContextPath(); // 只找项目名

取得 ActionMapping [ struts-config.xml 文件中 标签信息]

**
•processMapping(request, response, path)

protected ActionMapping processMapping( HttpServletRequest request, 		
		HttpServletResponse response, String path) 
					throws IOException { ActionMapping mapping = 			
					(ActionMapping)moduleConfig.findActionConfig(path); return ( mapping ); }

**
---------------------------------- findActionConfig( path )
从 ModuleConfig 里找 actionConfigs 集合,通过 path = “/login” 与集合中的 key 相匹配,取得该请求对应的 ActionMapping 对象
Key = “/login”,value = ActionMapping 对象 ( mapping ),取得 ActionMapping 对象后返回给调用方法 processMapping()
□取到该请求的 ActionMapping 对象后即可取得 标签与其中的各属性
<action path="/login" type=“com.struts.LoginAction” name=“loginForm”
scope=“request” // 一旦创建了表单Bean 对象,就将对象封装到scope 对应的内置对象中 – 如果不配置 scope,默认为 session validate=“false” // 标识不调用表单Bean 的 valicate() 方法 – 如果不配置 validate,默认为 true,会对表单中的数据进行验证

// 此标签为了创建 ActionForward 对象
// redirect 不写默认为 false,即转向方式为请求转发

创建 ActionForm

•processActionForm(request, response, mapping)

**protected ActionForm processActionForm( HttpServletRequest request, 
				HttpServletResponse response, ActionMapping mapping) {
						 ActionForm instance = RequestUtils.createActionForm( request, 
						 mapping, moduleConfig, servlet);**
						 }

一个静态方法,该方法的返回值就是一个表单Bean 对象 ActionForm

---------------------------------- createActionForm( request, mapping, moduleConfig, servlet)
**

public static ActionForm createActionForm(HttpServletRequest request,
			ActionMapping mapping,ModuleConfig moduleConfig,ActionServlet servlet) {
		   String attribute = mapping.getAttribute();
		   if (attribute == null) { return (null); } // 先找 attribute 属性值,如果没有  
		   再去找 name String name = mapping.getName(); 
		   	// 从 <action> 标签中取得 name="loginForm" 
		   	FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
			ActionForm instance = lookupActionForm(request, attribute, 	
			mapping.getScope());
			return createActionForm(config, servlet); } // 通过反射创建出 ActionForm

**rm 对象并返回给调用方法 process()
---------------------------------- findFormBeanConfig(name)
 从 ModuleConfig 里找 formBeans 集合,通过 name=“loginForm” 与集合中的 key 相匹配,取得 FormBeanConfig 对象
 key = “loginForm”,value = FormBeanConfig 对象 ( config ),返回对象给调用方法 processActionForm()

---------------------------------- 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); }
 从 request / session 内置对象中看有没有 ActionForm 对象,如果有就直接返回这个对象给调用方法 processActionForm()
 如果 scope = session,只会存在一个 ActionForm

收集数据到 ActionForm

•processPopulate(request, response, form, mapping)
protected void processPopulate( HttpServletRequest request, HttpServletResponse response,
ActionForm form,ActionMapping mapping) throws ServletException {
if (form == null) { return; } // 先判断 ActionForm 是不是一个空对象
form.reset(mapping, request); // 如果复写了表单Bean 的 reset() 方法,先对表单Bean 进行初始化
// 真正的收集方法,向方法中注入表单Bean和request 内置对象RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(), request);
---------------------------------- populate(form, mapping.getPrefix(), mapping.getSuffix(), request)
public static void populate( Object bean, String prefix, String suffix, HttpServletRequest request) throws ServletException {
HashMap properties = new HashMap(); // Map 集合,存放最终的收集后的属性
Enumeration names = null; // Enumeration 集合,自身迭代收集所有的 request 中的属性
// 如果不是上传,创建一个 Enumeration 集合对象存放 request 中所有的参数名,Multipart 上传的标记if (!isMultipart) { names = request.getParameterNames(); }
while (names.hasMoreElements()) { // 看文件位置指针下有没有元素
String name = (String) names.nextElement(); // 第一个参数名 username
String stripped = name; } // stripped 里的值就是集合中的第一个元素,也是 username
Object parameterValue = request.getParameterValues(name); // 将通过参数名找到的参数值存放在 parameterValue 中
properties.put(stripped, parameterValue); // stripped 为 key, 对应的属性值为 value
即:将 request 中的参数放在一个名为 properties 的Map 集合中 – key 为参数名,value 为参数值BeanUtils.populate(bean, properties); // 将 Map 里的参数名参数值,放在 ActionForm 中
---------------------------------- populate(bean, properties)
public static void populate(Object bean, Map properties) throws IllegalAccessException, InvocationTargetException {
// 迭代所有的参数名,将Map 里的所有参数名放在Set集合中后放在 Iterator 集合中,并迭代
Iterator names = properties.keySet().iterator();
while (names.hasNext()) {
String name = (String) names.next(); if (name == null) { continue; }
Object value = properties.get(name); // 通过参数名取得相应的参数值并存放
setProperty(bean, name, value); // 调用 setProperty 方法,相当于 bean.setName(value); 将数据封装到 ActionForm 里

•过程描述:
○从表单中获取所有的参数名放在Enumeration 集合中
○迭代 Enumeration 取得所有的元素
○从 request 中取得各元素对应的参数值
○将表单中的参数名和参数值分别放在 Map 集合中
○调用BeanUtils.populate(bean, properties); 静态方法,传入表单Bean 和 Map 集合
○在静态方法中调用 setProperty( bean,name,value) 方法,相当于 bean.setName( value ) – 数据封装到了 ActionForm 中

实例化 Action

---------------------------------- processActionCreate(request, response, mapping)
protected HashMap actions = new HashMap();
protected Action processActionCreate( HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException { String className = mapping.getType(); // 取得 Action 的类名 type = “com.struts.LoginAction”
synchronized (actions) { // 用一个 Map 对象来做一个同步锁,同一时刻只有一个线程可以拿到 Action 对象 [ 用 Map 实现单例 ]

// 从 actions 集合中通过 key 判断有没有已存在的 Action 对象,如果有就不创建对象,没有就创建出 Action 对象
instance = (Action) actions.get(className);
if (instance != null) { return (instance); } }
instance = (Action) RequestUtils.applicationInstance(className); // 通过反射创建 Action 对象
// 将通过反射创建出的 Action 对象放在 Map 集合中,此时的单例是 Map 集合的单例 [ 不是饥汉模式也不是饱汉模式 ] actions.put(className, instance); // key = “LoginAction”,value = Action 对象
return (instance) ; }
---------------------------------- applicationInstance(className)
return (applicationClass(className).newInstance());

执行 Action 中的 execute() 方法

---------------------------------- 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) { // 抛给 struts 一个异常
return ( processException(request, response, e, form, mapping)); } }
○返回给 struts 一个 ActionForward 对象 [ 封装 name / path 跳转路径 / redirect 跳转方式]

转向

---------------------------------- processForwardConfig(request, response, forward)
protected void processForwardConfig( HttpServletRequest request, HttpServletResponse response,
ForwardConfig forward) throws IOException, ServletException { String forwardPath = forward.getPath(); // 取得跳转路径
// 如果跳转方式是 false – 服务端跳转,为true – 客户端跳转
if (forward.getRedirect()) {
if (uri.startsWith("/")) { uri = request.getContextPath() + uri; } response.sendRedirect(response.encodeRedirectURL(uri));
} else {
doForward(uri, request, response); } // 服务端跳转

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值