下面以用户登录为例:部分需要参考的配置文件如下:
<form-beans >
<form-bean name="loginForm" type="com.hundsun.struts.form.LoginForm" />
</form-beans>
<action-mappings >
<action
attribute="loginForm"
input="/login.jsp"
name="loginForm"
path="/login"
scope="request"
validate="true"
type="com.hundsun.struts.action.LoginAction" />
</action-mappings>
struts有一个中央控制器ActionServlet,负责处理用户的url请求,ActionServlet在web.xml文件中配置,它继承了HttpServlet,其实就是一个普通的servlet。ActionServlet中有两个方法,如下:
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
ActionServlet会自动调用doGet()或doPost()方法。从中可以看出doGet(),doPost()直接调用了process(request, response)方法:
protected void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
ModuleUtils.getInstance().selectModule(request, getServletContext());
ModuleConfig config = getModuleConfig(request);
RequestProcessor processor = getProcessorForModule(config);
if (processor == null) {
processor = getRequestProcessor(config);
}
processor.process(request, response);
}
process方法继续调用RequestProcessor 的process(request, response)方法,process的部分源代码如下:
public void process(HttpServletRequest request,
HttpServletResponse response){
request = processMultipart(request);
String path = processPath(request, response);
if (path == null) {
return;
}
ActionMapping mapping = processMapping(request, response, path);
if (mapping == null) {
return;
}
ActionForm form = processActionForm(request, response, mapping);
processPopulate(request, response, form, mapping);
if (!processForward(request, response, mapping)) {
return;
}
Action action = processActionCreate(request, response, mapping);
if (action == null) {
return;
}
ActionForward forward =
processActionPerform(request, response,
action, form, mapping);
processForwardConfig(request, response, forward);
}
processMultipart(request);主要是用来处理file域,其实就是重写request得到属性的方法。
String path = processPath(request, response);截取用户提交的url地址,该方法主要的两句代码如下:
int slash = path.lastIndexOf("/");
int period = path.lastIndexOf(".");
此时的path="/login";接着我们来看
ActionMapping mapping = processMapping(request, response, path);主要源代码如下:
protected ActionMapping processMapping(HttpServletRequest request,
HttpServletResponse response,
String path)
throws IOException {
ActionMapping mapping = (ActionMapping)
moduleConfig.findActionConfig(path);
ActionConfig configs[] = moduleConfig.findActionConfigs();
for (int i = 0; i < configs.length; i++) {
if (configs[i].getUnknown()) {
mapping = (ActionMapping) configs[i];
request.setAttribute(Globals.MAPPING_KEY, mapping);
return (mapping);
}
}
}
我们先看ActionMapping mapping = (ActionMapping)moduleConfig.findActionConfig(path)方法。
moduleConfig类是个接口,他的实现类是moduleConfigImpl
public ActionConfig findActionConfig(String path) {
ActionConfig config = (ActionConfig) actionConfigs.get(path);
return config;
}
actionConfigs是个hashmap通过key=path="/login"获取,actionConfigs的这个值是在struts初始化的时候放进去的。
ok,现在ActionMapping已经得到,一个ActionMapping就是对应一个<action/>标签,它的key为 <action/>标签中的path的值,这里为"/login",其余的<action/>标签中的属性值就是value。
下面看:ActionForm form = processActionForm(request, response, mapping);
protected ActionForm processActionForm(HttpServletRequest request,
HttpServletResponse response,
ActionMapping mapping) {
ActionForm instance = RequestUtils.createActionForm
(request, mapping, moduleConfig, servlet);
if (instance == null) {
return (null);
}
if ("request".equals(mapping.getScope())) {
request.setAttribute(mapping.getAttribute(), instance);
} else {
HttpSession session = request.getSession();
session.setAttribute(mapping.getAttribute(), instance);
}
return (instance);
}
先看ActionForm instance = RequestUtils.createActionForm(request, mapping, moduleConfig, servlet);
public static ActionForm createActionForm(
HttpServletRequest request,
ActionMapping mapping,
ModuleConfig moduleConfig,
ActionServlet servlet) {
// Is there a form bean associated with this mapping?
String attribute = mapping.getAttribute();
if (attribute == null) {
return (null);
}
String name = mapping.getName();
FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
ActionForm instance = lookupActionForm(request, attribute, mapping.getScope());
return createActionForm(config, servlet);
}
String attribute = mapping.getAttribute();是来找attribute="loginForm"如果没有就直接返回,因为formbean我们不一定要创建。
这句String name = mapping.getName();是得到form的名字 name="loginForm"
接着是FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
public FormBeanConfig findFormBeanConfig(String name) {
return ((FormBeanConfig) formBeans.get(name));
}
formBeans也是个hashmap,里面存放的就是一个个<form-bean/>标签这里例子中的key="loginForm"
现在我们得到了一个FormBeanConfig。接着:
ActionForm instance = lookupActionForm(request, attribute, mapping.getScope());
private static ActionForm lookupActionForm(HttpServletRequest request, String attribute, String scope)
{
ActionForm instance = null;
HttpSession session = null;
if ("request".equals(scope)) {
instance = (ActionForm) request.getAttribute(attribute);
} else {
session = request.getSession();
instance = (ActionForm) session.getAttribute(attribute);
}
return (instance);
}
先在request和session找下是否存在这个FormBean,如果有就直接返回。如果instance为空,就继续创建createActionForm(config, servlet);
public static ActionForm createActionForm(FormBeanConfig config, ActionServlet servlet)
{
ActionForm instance = null;
instance = config.createActionForm(servlet);
return (instance);
}
public ActionForm createActionForm(ActionServlet servlet)
throws IllegalAccessException, InstantiationException {
Object obj = null;
// Create a new form bean instance
if (getDynamic()) {
obj = getDynaActionFormClass().newInstance();
} else {
obj = formBeanClass().newInstance();
}
ActionForm form = null;
if (obj instanceof ActionForm) {
form = (ActionForm)obj;
} else {
form = new BeanValidatorForm(obj);
}
return form;
}
通过动态代理得到一个formBean。
好了,现在我们看 Action action = processActionCreate(request, response, mapping);
protected Action processActionCreate(HttpServletRequest request,
HttpServletResponse response,
ActionMapping mapping)
throws IOException {
String className = mapping.getType();
Action instance = null;
synchronized (actions) {
instance = (Action) actions.get(className);
if (instance != null) {
return (instance);
}
instance = (Action) RequestUtils.applicationInstance(className);
instance.setServlet(this.servlet);
actions.put(className, instance);
}
return (instance);
}
String className = mapping.getType();得到的就是action的完整路径名,这里为com.hundsun.struts.action.LoginAction
synchronized (actions) actions是个hashmap,loginAction存在就返回,这里进行了同步,也就是说只会创建一个loginAction实例。接下看下面的代码,如果不存在就调用instance = (Action) RequestUtils.applicationInstance(className)
public static Object applicationInstance(String className)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
return (applicationClass(className).newInstance());
}
返回一个loginAction实例。
ActionForward forward =processActionPerform(request, response,action, form, mapping);
protected ActionForward
processActionPerform(HttpServletRequest request,
HttpServletResponse response,
Action action,
ActionForm form,
ActionMapping mapping)
throws IOException, ServletException {
return (action.execute(mapping, form, request, response));
}
这里直接调用了action类的execute方法,返回一个ActionForward,ActionForward类里存放着对应<action/>标签下的所有的forward信息。最后执行processForwardConfig(request, response, forward);
protected void processForwardConfig(HttpServletRequest request,
HttpServletResponse response,
ForwardConfig forward)
throws IOException, ServletException {
if (forward == null) {
return;
}
String forwardPath = forward.getPath();
String uri = null;
if (forwardPath.startsWith("/")) {
uri = RequestUtils.forwardURL(request, forward, null);
} else {
uri = forwardPath;
}
if (forward.getRedirect()) {
if (uri.startsWith("/")) {
uri = request.getContextPath() + uri;
}
response.sendRedirect(response.encodeRedirectURL(uri));
} else {
doForward(uri, request, response);
}
}
。。。。。
分两种情况进行转发,一种是: response.sendRedirect(response.encodeRedirectURL(uri));
另二种是:doForward(uri, request, response);该方法里主要的两句代码是:
RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
rd.forward(request, response);
OVER!
转自http://lovedance.blogbus.com/logs/36997014.html