看struts2源代码已有一段时日,从今天開始,就做一个总结吧。

首先,先看看怎么调试struts2源代码吧,主要是下面步骤:

使用Myeclipse创建一个webproject

导入struts2须要的jar包

如图:

让jar包关联源文件

在上图中的jar包右键,选择properties->java source attach,假设关联成功,双击jar包下的某个class文件就会显示java源码了。

双击.class文件,在源码关键地方设置断点

部署project到Tomcat

Tomcat以Debug方式启动

经过以上步骤,就可以执行单步调试了,这样就能够非常方便的查看代码的执行状态了。

struts2框架作为MVC框架,主要作用就是帮助处理请求,以一种与web容器无关的方式。也就是说,处理请求时能够不使用HttpServletRequest等类。struts2採用Filter来拦截请求,推断假设是struts2能够处理的,请求就进入struts2框架进行处理,否则请求进入下一个Filter。

先从Filter的初始化開始来看struts2吧,由于这也是struts2框架初始化的过程。

ok,我们看看struts2的StrutsPrepareAndExecuteFilter类的init()方法:

public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
Dispatcher dispatcher = null;
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);//仅仅是进行了一层薄薄的封装
init.initLogging(config);//初始化用户在配置filter时定义的logger
dispatcher = init.initDispatcher(config);//创建一个转发器,并初始化
init.initStaticContentLoader(config, dispatcher);//初始化静态资源载入器 prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); postInit(dispatcher, filterConfig);
} finally {
if (dispatcher != null) {
dispatcher.cleanUpAfterInit();
}
init.cleanup();
}
}

从以上代码能够归纳出,初始化主要完毕下面这些事情:

1.封装init()的參数filterConfig成struts2定义的FilterHostConfig

仅仅是进行了一层薄薄的封装,代码例如以下:

public class FilterHostConfig implements HostConfig {

    private FilterConfig config;

    public FilterHostConfig(FilterConfig config) {
this.config = config;
}
public String getInitParameter(String key) {
return config.getInitParameter(key);
} public Iterator<String> getInitParameterNames() {
return MakeIterator.convert(config.getInitParameterNames());
} public ServletContext getServletContext() {
return config.getServletContext();
}
}

2.初始化日志记录器,假设用户在web.xml中配置filter时配置了loggerFactory參数的话

通过InitOperations类的initLogging()。InitOperations类主要是封装了一些初始化操作,下面是该类的全部方法,从名字也能够看出方法的功能。

public class InitOperations {
public InitOperations()
public void initLogging( HostConfig filterConfig )
public Dispatcher initDispatcher( HostConfig filterConfig )
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher )
public Dispatcher findDispatcherOnThread()
private Dispatcher createDispatcher( HostConfig filterConfig )
public void cleanup()
public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher )
private List<Pattern> buildExcludedPatternsList( String patterns )
}

3.创建Dispatcher并初始化

Dispatcher在struts2中是一个非常重要的类,它的工作就是将filter拦截到的请求转入struts2的请求处理模块。当然,首先Dispatcher会被初始化,它的初始化方法init()但是干了非常多的活呢。这部分在后面会细细的解说,先看看大概是如何一个过程吧。在InitOperations类中:

public Dispatcher initDispatcher( HostConfig filterConfig ) {
Dispatcher dispatcher = createDispatcher(filterConfig);
dispatcher.init();
return dispatcher;
}
private Dispatcher createDispatcher( HostConfig filterConfig ) {
Map<String, String> params = new HashMap<String, String>();
for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
String name = (String) e.next();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
return new Dispatcher(filterConfig.getServletContext(), params);
}

这里filter配置的參数会被保存如Dispatcher对象中,配置如:

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>filterParam</param-name>
<param-value>abc</param-value>
</init-param>
</filter>

4.初始化静态资源载入器

public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {
StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
loader.setHostConfig(filterConfig);
return loader;
}

在完毕了Dispatcher的初始化之后,struts2维护的一个容器Container就创建完毕了,能够使用了。这里通过container创建一个StaticContentLoader对象。

StaticContentLoader是接口,看看该接口声明了哪些方法:

public interface StaticContentLoader {
public boolean canHandle(String path);
public abstract void setHostConfig(HostConfig filterConfig);
public abstract void findStaticResource(String path, HttpServletRequest request, HttpServletResponse response)
throws IOException;
}

struts2有一个实现类为DefaultStaticContentLoader类。在普通情况下,struts2是不会处理静态资源的请求的,除非请求的路径是以struts或static开头,如有个test应用,那么请求必须是/test/struts/...或者/test/static/...这样才会处理。

假设struts2框架不处理静态资源的请求的话,谁来处理呢?自然是web容器了,比方tomcat。在StrutsPrepareAndExecuteFilter中:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
<span style="white-space:pre"> </span>...
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
...
}

能够看到,假设不处理,那么调用chain.doFilter(),请求也就不进入struts2框架了。

那么,假设要让struts2框架处理这种请求,应该怎么做呢?

首先,自然是请求的路径要以struts或static开头了。

然后,静态资源应该存放在应用的例如以下几个包之中的一个:

struts

org.apache.struts2.static

template

org.apache.struts2.interceptor.debugging

也能够自己在filter配置參数指定包名:

<init-param>
<param-name>packages</param-name>
<param-value>abc</param-value>
</init-param>

假设有多个包的话,能够用逗号分隔。

如此就可以。

5.创建PrepareOperations对象和ExecuteOperations对象

PrepareOperations和ExecuteOperations有什么用呢?和InitOperations类似,封装一些操作。仅仅只是InitOperations是封装初始化的操作,而前两者则是封装请求预处理和请求处理的操作,当处理请求时方法被调用。先看PrepareOperations有哪些操作:

public class PrepareOperations {
public PrepareOperations(ServletContext servletContext, Dispatcher dispatcher)
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response)
public void cleanupRequest(HttpServletRequest request)
public void assignDispatcherToThread()
public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response)
public HttpServletRequest wrapRequest(HttpServletRequest oldRequest)
public ActionMapping findActionMapping
(HttpServletRequest request, HttpServletResponse response)
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup)
public void cleanupDispatcher()
public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> excludedPatterns )
private String getUri( HttpServletRequest request )
}

ExecuteOperations就简单得多了:

public class ExecuteOperations {
private ServletContext servletContext;
private Dispatcher dispatcher; public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {
this.dispatcher = dispatcher;
this.servletContext = servletContext;
} /**
* Tries to execute a request for a static resource
* @return True if it was handled, false if the filter should fall through
* @throws IOException
* @throws ServletException
*/
public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// there is no action in this request, should we look for a static resource?
String resourcePath = RequestUtils.getServletPath(request); if ("".equals(resourcePath) && null != request.getPathInfo()) {
resourcePath = request.getPathInfo();
} StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
if (staticResourceLoader.canHandle(resourcePath)) {
staticResourceLoader.findStaticResource(resourcePath, request, response);
// The framework did its job here
return true; } else {
// this is a normal request, let it pass through
return false;
}
} /**
* Executes an action
* @throws ServletException
*/
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
dispatcher.serviceAction(request, response, servletContext, mapping);
}
}

关于请求的处理,后面具体讲。这里就当做是一个热身吧。

6.封装配置filter时指定的不处理的action请求的pattern成List<Pattern>

这个配置是通过STRUTS_ACTION_EXCLUDE_PATTERN这个常量设置的。在struts.xml或者struts.properties文件里配置。

7.完毕一些清理工作

事实上也没清理多少东西了。

ok,初始化的基本流程分析完了,但当中Dispatcher的初始化还是一个黑盒。所下面一篇struts2源代码学习之初始化(二)就具体分析Dispatcher的初始化。

struts2源代码学习之初始化(一)的更多相关文章

  1. struts2源代码分析(个人觉得非常经典)

    读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验,那么千万不要想当然地以为这一章可以跳过.实际上Struts1.x与Struts2并无我们想象的血缘关系.虽然Struts2的开 ...

  2. 读Flask源代码学习Python--config原理

    读Flask源代码学习Python--config原理 个人学习笔记,水平有限.如果理解错误的地方,请大家指出来,谢谢!第一次写文章,发现好累--!. 起因   莫名其妙在第一份工作中使用了从来没有接 ...

  3. struts2框架学习之第一天

    day01 Struts2概述 1 什么是框架 试想一下,人与人之间不同之处多,还是相同之处多呢?当然是相同之处多,不同之处少!人都有头,而且头都在脖子上面! 软件之间也是相同之处多,不同之处少,框架 ...

  4. JDK源代码学习系列04----ArrayList

                                                                             JDK源代码学习系列04----ArrayList 1 ...

  5. igmpproxy源代码学习——igmpProxyInit()

    igmpproxy源代码学习--igmpProxyInit()函数详解,igmpproxy初始化 在运行igmpproxy的主程序igmpproxyRun()之前需要对igmpproxy进行一些配置, ...

  6. JDK源代码学习系列03----StringBuffer+StringBuilder

                         JDK源代码学习系列03----StringBuffer+StringBuilder 因为前面学习了StringBuffer和StringBuilder的父类 ...

  7. Java之struts2框架学习

    Java之struts2框架学习 About Struts2 Struts也是一款MVC框架 , Struts2是Struts的下一代产品,是在Struts1和WebWork的技术基础上进行了合并的全 ...

  8. Swoole源代码学习记录(十五)——Timer模块分析

    swoole版本号:1.7.7-stable Github地址:点此查看 1.Timer 1.1.swTimer_interval_node 声明: // swoole.h 1045-1050h ty ...

  9. [Java] LinkedList / Queue - 源代码学习笔记

    简单地画了下 LinkedList 的继承关系,如下图.只是画了关注的部分,并不是完整的关系图.本博文涉及的是 Queue, Deque, LinkedList 的源代码阅读笔记.关于 List 接口 ...

随机推荐

  1. xcode升级,报错 libxml/tree.h not found (Xcode4.6解决方案)

    转:http://blog.csdn.net/yangxuanlun/article/details/8639075 Xcode升级到4.6以后,他妈的,libxml/tree.h找不到了,搞了大半天 ...

  2. Java中实现复制文件或文件夹

     拷贝一个文件的算法比较简单,当然,可以对它进行优化,比如使用缓冲流,提高读写数据的效率等.但是在复制文件夹时,则需要利用Flie类在目标文件夹中创建相应的目录,并且使用递归方法. [java] vi ...

  3. codeforces 700C Break Up 暴力枚举边+边双缩点(有重边)

    题意:n个点,m条无向边,每个边有权值,给你 s 和 t,问你至多删除两条边,让s,t不连通,问方案的权值和最小为多少,并且输出删的边 分析:n<=1000,m是30000  s,t有4种情况( ...

  4. 仿酷狗音乐播放器开发日志二十四 选项设置窗体的实现(附328行xml布局源码)

    转载请说明原出处,谢谢~~ 花了两天时间把仿酷狗的选项设置窗体做出来了,当然了只是做了外观.现在开学了,写代码的时间减少,所以整个仿酷狗的工程开发速度减慢了.今天把仿酷狗的选项设置窗体的布局代码分享出 ...

  5. [算法] 希尔排序 Shell Sort

    希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进.该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 希尔排序实质上是一种分组插入方法.它的基本思想是: ...

  6. homework 08_2 C++11新特性作业之二

    ---恢复内容开始--- 1.使用Lambda表达式计算“hello world!”中字母e和i的数量 下面是代码: #include "stdafx.h" #include< ...

  7. 自定义控件和XControl控件

    (1)LabVIEW的自定义控件,实际上就是对LabVIEW自带的控件的一种修改,但是这种修改只能改变它的外观,即大小.颜色.位置等等,但是功能是改变不了的.如你对一个按钮进行自定义控件,无论怎么改, ...

  8. JavaIO(01)File类详解

    File类 file类中的主要方法和变量   常量: 表示路径的分割符:(windows) 作用:根据java可移植性的特点,编写路径一定要符合本地操作系统要求的分割符: public static ...

  9. Java学习笔记(二):String

    String 在Java中String是作为引用对象存在的一种数据类型,用来保存字符串. 实例化和赋值 //直接声明 String s1 = "Hello world!"; //通 ...

  10. Objective-C :Category

    Category 引入 在日常的开发中,可能会碰到这样的需求:给某个类增加方法.比如说,需要给NSString类增加一个打印的方法.当然,我们可以新建一个类比如TestString,并继承NSStri ...