上篇文章已经介绍了struts2的简单使用,现在开始源码的学习。

本篇主要介绍struts2的初始化。对应的源码为StrutsPrepareAndExecuteFilter中的init方法。

先贴源码:

public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter { //这里的StrutsStatics接口中没有方法,只有常量
protected PrepareOperations prepare;
protected ExecuteOperations execute;
    protected List<Pattern> excludedPatterns = null;
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
Dispatcher dispatcher = null;
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher); prepare = new PrepareOperations(dispatcher);
execute = new ExecuteOperations(dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); postInit(dispatcher, filterConfig);
} finally {
if (dispatcher != null) {
dispatcher.cleanUpAfterInit();
}
init.cleanup();
}
}
一个个对以上的对象跟方法进行分析:

1. InitOperations init = new InitOperations(); --封装了一些初始化的操作

源码中的大纲视图(具体方法下文会详细讲解):

从这个视图我们可以发现,这个对象中封装的都是一些初始化的方法(从名字也不难发现),对照我们

StrutsPrepareAndExecuteFilter中的init方法的源码,也可以得出相同的结论。

  2.FilterHostConfig config = new FilterHostConfig(filterConfig);
 --这里主要是对filterConfig进行了简单的封装

源码如下:

    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();
}
}
  可以发现,这个对象只是对FiterConfig进行了简单的封装,   getInitParameterNames(),这个方法,将枚举类型的参数换成了Iterator

3.init.initLogging(config); --初始化日志记录器

 public void initLogging( HostConfig filterConfig ) {
        String factoryName = filterConfig.getInitParameter("loggerFactory");
if (factoryName != null) {
try {
Class cls = ClassLoaderUtil.loadClass(factoryName, this.getClass());
LoggerFactory fac = (LoggerFactory) cls.newInstance();
LoggerFactory.setLoggerFactory(fac);
} catch ( InstantiationException e ) {
System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch ( IllegalAccessException e ) {
System.err.println("Unable to access logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch ( ClassNotFoundException e ) {
System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
e.printStackTrace();
}
}
}

4.dispatcher = init.initDispatcher(config);初始化转发器

    这个类是struts中很重要的一个类,它的工作就是将filter拦截到的请求转发

struts2的请求处理模块。这句代码的作用是初始化一个转发器,或者叫分发器。

源码如下:

 一:
// 这部分代码,只是执行了创建了一个dispatcher跟执行dispatcher的init方法,并返回了一个对象,
  //  所以我们继续跟踪dcreateDispatcher跟ispatcher的init方法
 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);
}
 

三:
源码如下:

 public void init() {
if (configurationManager == null) {
configurationManager = createConfigurationManager(DefaultBeanSelectionProvider.DEFAULT_BEAN_NAME);
} try {             init_FileManager();
           
            init_DefaultProperties(); // [1]
           
            init_TraditionalXmlConfigurations(); // [2]
           
            init_LegacyStrutsProperties(); // [3]
           
            init_CustomConfigurationProviders(); // [5]
           
            init_FilterInitParameters() ; // [6]
           
            init_AliasStandardObjects() ; // [7]
           
Container container = init_PreloadConfiguration();             container.inject(this);
           
            init_CheckWebLogicWorkaround(container);
           
if (!dispatcherListeners.isEmpty()) {
for (DispatcherListener l : dispatcherListeners) {
l.dispatcherInitialized(this);
}
}
            
             errorHandler.init(servletContext); } catch (Exception ex) {
if (LOG.isErrorEnabled())
LOG.error("Dispatcher initialization failed", ex);
throw new StrutsException(ex);
}
}
由于篇幅原因,这篇文章中暂时不对这段代码做详细的解释,只做一些简单的注释,下篇文章专门解释这段代码

5.init.initStaticContentLoader(config, dispatcher); --初始化静态资源加载器

        在完成对dispatcher对象的初始化后,strtus2维护的一个容器Container就创建完成了,可以使用了,

这里通过dispatcher对象获取一个container的实例(container本身是一个接口),再通过containerd的

getInstance方法获取了一个StaticContentLoader对象。

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

我们发现StaticContentLoader也是一个接口,继续看它声明的方法

查阅大纲视图:

再查找它的实现类DefaultStaticContentLoader

(只有这一个实现类)

 public boolean canHandle(String resourcePath) {
return serveStatic && (resourcePath.startsWith("/struts/") || resourcePath.startsWith("/static/"));
}
从这段代码中可以看出,只有请求路径中包含struts或者static时这个方法才会返回true

实际上,在一般情况下strtus2是不会处理静态资源请求的,除非请求的路径是以struts或static开头,如

有个test应用,那么请求必须是/test/struts/...或者/test/static/...这样才会处理。

在StrutsPrepareAndExecuteFilter中的有如下代码:

很明显,当判断为不需要处理时,会直接放行。

   6.       prepare = new PrepareOperations(dispatcher);  --实例化http请求预处理对象
execute = new ExecuteOperations(dispatcher); --示例化http请求处理对象

PrepareOperations和ExecuteOperations有什么用呢?和InitOperations类似,封装一些操作。只

不过InitOperations是封装初始化的操作,而前两者则是封装请求预处理和请求处理的操作,当处理请求时方法

被调用。先看PrepareOperations有哪些操作,查看源码大纲视图如下:

其次是ExecuteOperations的源码,相对来说简单很多:

public class ExecuteOperations {

    private Dispatcher dispatcher;

    @Deprecated
public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {
this.dispatcher = dispatcher;
} public ExecuteOperations(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
} /**
* 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, mapping);
}
}

这里对这两段源码也不做详细讲解,下一节再细说。

7.this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

        封装配置filter时指定的不处理的action请求的pattern成List<Pattern>,源码如下

    public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) {
return buildExcludedPatternsList(dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN));
} private List<Pattern> buildExcludedPatternsList( String patterns ) {
if (null != patterns && patterns.trim().length() != 0) {
List<Pattern> list = new ArrayList<Pattern>();
String[] tokens = patterns.split(",");
for ( String token : tokens ) {
list.add(Pattern.compile(token.trim()));
}
return Collections.unmodifiableList(list);
} else {
return null;
}
}

8.postInit(dispatcher, filterConfig); --回调方法,用做用户拓展

这个方法实际上什么都没做,源码如下:

protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
          }

9.init.cleanup();--垃圾清理

源码如下:

public void cleanup() {
ActionContext.setContext(null);
}
    public static void setContext(ActionContext context) {
actionContext.set(context);
}

实际上就是将actionContext中的ActionContext对象置为null,我们跟踪actionContext这个对象发现,它其

实是一个本地线程变量,所以这个操作实际上就是在清空线程中的ActionContext对象,这里不对这个对象做太

多说明,接下来的文章会详细介绍。

public class ActionContext implements Serializable {

    static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();

源码的第一篇学习笔记就写到这。希望多多交流,有误的地方欢迎大家指正!

struts2初始化探索(一)的更多相关文章

  1. struts2源码分析-初始化流程

    这一篇文章主要是记录struts.xml的初始化,还原struts2.xml的初始化流程.源码依据struts2-2.3.16.3版本. struts2初始化入口,位于web.xml中: <fi ...

  2. Struts2.3.15.1源码浅析

    Struts2 两大运行主线: 1.初始化主线:初始化主线主要是为Struts2创建运行环境(此处的环境与Struts2身处的Web环境是有区别的),初始化入口StrutsPrepareAndExec ...

  3. struts2中各种值栈问题

    struts2中OGNL和 ValueStack(一) 收藏 学习的时候,总分不清楚在struts2中页面的传值和取值是怎么来完成的,所以从网上搜了很多资料,现在把这些资料总结写,留着以后参考..看完 ...

  4. 《Struts2技术内幕》学习笔记

    第2.3章 基础 三种类模式:属性-行为模式.属性模式.行为模式. 其中属性模式有:PO(持久化对象).BO(业务对象).VO(值对象).DTO(传输数据对象).FromBean(页面对象)他们是对J ...

  5. Struts2 之值栈

    值栈(ValueStack) http://www.cnblogs.com/bgzyy/p/8639893.html 这是我的有关 struts2 的第一篇文章,对于里面我们说到的一个 struts2 ...

  6. [转] valuestack,stackContext,ActionContext.之间的关系

    三者之间的关系如下图所示: ActionContext  一次Action调用都会创建一个ActionContext  调用:ActionContext context = ActionContext ...

  7. valuestack,stackContext,ActionContext.之间的关系

    者之间的关系如下图所示: relation ActionContext 一次Action调用都会创建一个ActionContext 调用:ActionContext context = ActionC ...

  8. 剖析SSH核心原理(一)

      在我前面的文章中,也试图总结过SSH,见 http://blog.csdn.net/shan9liang/article/details/8803989 ,随着知识的积累,总感觉以前说得比较笼统, ...

  9. 个人笔记--Servlet之过滤器实现权限拦截

    一.编写一个Java类实现javax.servlet.Filter接口 package cn.edu.sxu.filter; import java.io.IOException; import ja ...

随机推荐

  1. Mac Jenkins+fastlane 简单几步实现iOS自动化打包发布 + jenkins节点设置

    最近在使用jenkins 实现ios自动化打包发布蒲公英过程实践遇到了一些坑,特意记录下来方便有需要的人. 进入正题: 一.安装Jenkins 1.Mac上安装Jenkins 遇到到坑 因为 Jenk ...

  2. 小L的直线

    小学时期的小L发现自己很有艺术细胞,于是买了一块画板,但是他的绘画水平使得他只能连接两点画出一条线段.有一天他决定在一张有n个点的图上作画,即他可以把这n个点任意连接.大家认为平行线是非常不美观的,于 ...

  3. React AntDesign 引入css

    React项目是用umi脚手架搭建的AntDesign,用到一个第三方表格组件Jexcel,npm install 之后组件的样式加载不上,犯了愁,翻阅各种资料,踏平两个小坑. 大家都知道,安装完成的 ...

  4. 百度智能云虚拟主机 Typecho 分类功能失效 | 开启伪静态地址

    出现的问题 $this->is() 方法失效,无法正确判断 archive.category.tags 页面类型. 点击分类页面.归档页面时,虽然 URL 是正确的,但网页内容却是 index. ...

  5. self不明白什么意思,我来帮助你了解self的含义

    先看下面这段代码 # 用函数模仿类def dog(name, gender): def jiao(dog1): print('%s汪汪叫' % dog1["name"]) def ...

  6. MySQL服务端恶意读取客户端文件漏洞 (DDCTF2019和国赛均涉及到这个漏洞)

    mysql协议中流程和go语言实现的恶意mysql服务器:https://blog.csdn.net/ls1120704214/article/details/88174003 poc :https: ...

  7. WTF Python:有趣且鲜为人知的Python特性

    Python 是一个设计优美的解释型高级语言,它提供了很多能让程序员感到舒适的功能特性.但有的时候,Python 的一些输出结果对于初学者来说似乎并不是那么一目了然. 这个有趣的项目意在收集 Pyth ...

  8. 用long类型让我出了次生产事故,写代码还是要小心点

    昨天发现线上试跑期的一个程序挂了,平时都跑的好好的,查了下日志是因为昨天运营跑了一家美妆top级淘品牌店,会员量近千万,一下子就把128G的内存给爆了,当时并行跑了二个任务,没辙先速写一段代码限流,后 ...

  9. 痞子衡嵌入式:大话双核i.MXRT1170之Cortex-M7与Cortex-M4互相激活之道

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7与Cortex-M4内核互相激活的方法. 痞子衡最近在深耕i.MXRT1170这颗划时代的 ...

  10. PHP入门-1

    基本数据类型: 1.整形 2.浮点型 3.字符串 4.布尔型 5.数组和对象 6.null 7.资源类型 8.伪类型 由于php是弱语言,所以他的数据类型不用自己来定义.定义一个数据类型,$name ...