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