struts2框架执行流程

struts2框架执行流程struts 源码解析ActionServlet 的执行流程•Tomcat 及封装配置2 // web.xml 文件的 标签,配置则服务器启动则创建ActionServlet,否则访问时创建Tomcat 一启动就将 web.xml 文件读取到内存,读取 标签创建出中央控制器

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.dousername=“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); } // 通过反射创建出 ActionFor

**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); } // 服务端跳转

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/15707.html

(0)
上一篇 2024年 5月 19日
下一篇 2024年 5月 19日

相关推荐

关注微信