Struts 简单分析
一. ActionServlet
Struts的核心控制器,web.xml的配置,使它可以截获所有 *.do 的请求
<!-- Standard Action Servlet Configuration -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- Standard Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
ActionServlet就是一个普通的servlet,继承了HttpServlet,覆写了doPost和doGet方法。
doPost()或doGet()均调用Process(),Process()内部主要为:
RequestProcessor processor = getProcessorForModule(config);
processor.process(request, response);
RequestProcessor则是struts最核心的类,可以看出所有的请求最终都由此类处理。
RequestProcessor的process(request, response)方法详细处理:
1.截取URL
// Identify the path component we will use to select a mapping
String path = processPath(request, response);
截取URL,若为null,直接返回。
2.根据path,获取匹配的ActionMapping,每个Action对应一个ActionMapping
a.// Identify the mapping for this request
ActionMapping mapping = processMapping(request, response, path);
b.// Is there a mapping for this path?
ActionMapping mapping = (ActionMapping) moduleConfig.findActionConfig(path);
moduleConfig是ModuleConfig的对象,ModuleConfig是一个接口,定义了对struts-config.xml文件的操作,具体由ModuleConfigImpl实现,对findActionConfig()方法的实现为:
ActionConfig config = (ActionConfig) actionConfigs.get(path);
actionConfigs是一个HashMap。当ActionServlet第一次实例化得时候,就读取struts-config.xml,所有的配置都读入到HsahMap,并保存到ServletContext的范围内,HashMap的“键值对”中key为path,value为ActionMapping 的实例。
ActionMapping继承ActionConfig,则根据path 得到对应Action的配置信息。
3.处理ActionForm
a.// Process any ActionForm bean related to this request
ActionForm form = processActionForm(request, response, mapping);
b.// Create (if necessary) a form bean to use
ActionForm instance = RequestUtils.createActionForm
(request, mapping, moduleConfig, servlet);
c.// Look up the form bean configuration information to use
String name = mapping.getName();
FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
moduleConfig就是配置文件的一套操作的接口。并且FormBeanConfig也是保存在一个HashMap中,key为name,value为FormBeanConfig。返回配置信息。若不存在直接返回,因为不配置ActionForm是正确的。
ActionForm instance = lookupActionForm(request, attribute, mapping.getScope());
return createActionForm(config, servlet);
先查找在mapping.getScope()的范围(request或session)内是否存在ActionForm实例,若存在并且可用的话,直接返回这个ActionForm实例;若不存在可用ActionForm实例,则根据配置信息实例化ActionForm,并根据mapping.getScope()将ActionForm的实例保存到session或request中。
d.获取表单数据,填充ActionForm的实例:
processPopulate(request, response, form, mapping);包含:
form.reset(mapping, request);重置方法,即填充数据之前可以给From设置初始 值,此方法可以覆写。
names = request.getParameterNames();获取表单的name数组。
while(names.length){
parameterValue = request.getParameterValues(name);
properties.put(name, parameterValue);
} 迭代循环获取所有的表单数据,properties是一个HashMap。
BeanUtils.populate(form, properties);调用第三方组件,给from正式填充值。
e.// Validate any fields of the ActionForm bean, if applicable
进行一定得表单验证,调用ActionForm的public ActionErrors validate()方法,进行一定得验证,此方法可以覆写。
4.Action
// Create or acquire the Action instance to process this request
Action action = processActionCreate(request, response, mapping);
对于同一个Action,是单实例的模式,切记。
ActionForward action.execute(mapping, form, request, response)
执行execute方法,返回ActionForward。
5.根据得到的ActionForward,进行转发或重定向,返回相应的视图层。
二.问题:
1. 读取struts-config.xml文件,保存在Map中,那这个Map是作为ActionServlet的一个实例变量呢?还是存放在ServletContext里面?
我的理解:不管是作为ActionServlet的一个实例变量,还是存放在ServletContext中,都是线程不安全的。ActionServlet的init()方法读取配置文件,不管是作为ActionServlet的实例变量,还是存放在ServletContext中,都能保证它在整个应用中一直生存在内存中。
2. Action的单实例,应该怎么理解?
一个线程 --- 获取RequestProcessor processor 对象,调用process()
RequestProcessor processor = getProcessorForModule(config);
if (processor == null) {
processor = getRequestProcessor(config);
}
processor.process(request, response);
/**
* Returns the RequestProcessor for the given module or null if one does not exist. This method will not create a RequestProcessor.
* @param config The ModuleConfig.
*/
private RequestProcessor getProcessorForModule(ModuleConfig config) {
String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
return (RequestProcessor)getServletContext().getAttribute(key);
}
protected synchronized RequestProcessor getRequestProcessor(ModuleConfig config) throws ServletException {
// 实例化RequestProcessor processor
String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
getServletContext().setAttribute(key, processor);
}
config.getPrefix()是请求URI的一部分,构造一个key。这样是不是说对同一个Action的请求,只有一个RequestProcessor对象?
---- 。。。。 --- 生成Action的时候,代码片段为:
String className = mapping.getType();
synchronized (actions) {
//Return any existing Action instance of this class
instance = (Action) actions.get(className);
if (instance != null) {
return (instance);
}
try {
//Create and return a new Action instance
instance = (Action)RequestUtils.applicationInstance(className);
} catch (Exception e) {}
actions.put(className, instance);
}
protected HashMap actions = new HashMap(),actions作为类RequestProcessor 的实例变量;我的理解,由代码可以看出actions中保存的是Action的一个单实例 。。。这样的话,对于同一个Action的请求,只有一个RequestProcessor对象,只有一个Action实例,的确会出现线程安全的问题!
struts1自己的理解
最新推荐文章于 2010-07-14 15:15:48 发布