struct2初始化
从上篇博文,我解析过,struct2工作的起点是struct2设计的一个过滤器org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter。Tomcat启动的时候会自动运行这个过滤器的init()方法,在这个init()方法会解析配置文件struct*.xml,搭建struct2运行所需的环境。下面我们就来详细介绍了这个方法。
代码清单:StrutsPrepareAndExecuteFilter.init()
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
//实例化并初始化Dispatcher对象
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
//实例化PrepareOperations对象
prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
//实例化ExecuteOperations对象
execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
//处理黑名单
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
//这个是空方法,用于扩展
postInit(dispatcher, filterConfig);
} finally {
//清空actionContext
init.cleanup();
}
}
在初始化主要做了三件事情:
①实例化一个封装配置信息的对象Dispatcher;
②实例化一个处理action请求的对象prepareOperations对象;
③实例化一个执行action请求对象的excuteOperations对象;
下面就对上面的每行代码做详细解析:
一、初始化一个initOperations对象
InitOperations init = new InitOperations();
initOperations只是一个初始化struct2的对象,我们可以调用里面的方法初始化struct2,如intDispacher实例并初始化Dispatcher对象,initLogging()初始化日志信息;initStaticContentLoader加载静态资源等等,这里直接用new方法。很简单。
二、实例化一个Dispacher对象
代码清单:实例化一个Dispacher对象
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
Dispatcher dispatcher = init.initDispatcher(config);
我们先来看initDispacher这个方法,看完你就会知道前面两行代码是干嘛用的了。。
代码清单:initDispatcher
public Dispatcher initDispatcher( HostConfig filterConfig ) {
//实例化一个Dispacher对象
Dispatcher dispatcher = createDispatcher(filterConfig);
//初始化Dispacher
dispatcher.init();
return dispatcher;
}
从这里我们可以看到,这个initDispacher方法主要做二件事:
①实例化一个Dispacher对象
②对这个Dispacher对象进行初始化(这里读配置文件信息,过程很复杂,下篇博文我用一个专题来介绍)
struct2是如何来创建这个Dispacher对象的呢?
代码清单:createDispatcher
private Dispatcher createDispatcher( HostConfig filterConfig ) {
//把web.xml中配置的params封装到一个map中
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);
}
//Dispacher构造函数
return new Dispatcher(filterConfig.getServletContext(), params);
}
从Dispacher构造函数可以看到,需要传进两个参数,一个是ServletContext,一个是params,这两个参数封装了web.xml的配置信息,我们都可以从tomcat提供给我们的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();
}
}
filterConfig是一个接口,tomcat都已帮我实现了这些方法,我们直接用这个对象就可以了。这里struct2对这个对象进行了封装。
FilterHostConfig config = new FilterHostConfig(filterConfig);
这里你知道initDispacher方法前面的那行代码是干嘛用了吧?initDispacher这个主要是初始化日志信息,对代码没多大影响,这里就忽略了。下面讨论的日志和异常信息都会忽略。
struct2对filterConfig成封装filterHostConfig对象,并把web.xml配置的params信息封装到一个map中,然后把这两个作为参数,实例化了一个Dispacher对象,然后在Dispacher里面解析配置文件搭建struct2的运行环境(下篇博文详谈)。
三、加载静态资源
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {
//实例化一个StaticContentLoader对象
StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
//把静态资源路径放进一个pathPrefixes数组
loader.setHostConfig(filterConfig);
return loader;
}
把静态资源路径放进一个pathPrefixes数组,这里是把org.apache.struts2.static和template 和org.apache.struts2.interceptor.debugging和 static和web.xml中配置的package路径保存到一个字符数组中。
代码清单:
protected String[] pathPrefixes;
public void setHostConfig(HostConfig filterConfig) {
//获取web.xml中配置的的packages属性
String param = filterConfig.getInitParameter("packages");
//获取静态资源路径
String packages = getAdditionalPackages();
//把5个资源路径以空格拼接起来
if (param != null) {
packages = param + " " + packages;
}
//把上面的字符串分割到一个字符数组中
this.pathPrefixes = parse(packages);
initLogging(filterConfig);
}
① 上面的getAdditionalPackages() 是指获取其他静态资源的包。
protected String getAdditionalPackages() {
return "org.apache.struts2.static template org.apache.struts2.interceptor.debugging static";
}
这里固定了默认加载4个包,一个是org.apache.struts2.static,property属性文件就放在这里面,如default.properties;default.properties存放struct2.xml中配置的<contant>的默认信息。而template是模板文件,存放了4个主题,如simple,xhtml等等,这些都是CSS样式,如果用到struct2做界面,就会用到这些文件;
②parse
protected String[] parse(String packages) {
if (packages == null) {
return null;
}
List<String> pathPrefixes = new ArrayList<String>();
//以逗号和回车(\n)跳格(\t)分割字符串
StringTokenizer st = new StringTokenizer(packages, ", \n\t");
while (st.hasMoreTokens()) {
//把点换成/
String pathPrefix = st.nextToken().replace('.', '/');
//给每个路径的结尾加/
if (!pathPrefix.endsWith("/")) {
pathPrefix += "/";
}
pathPrefixes.add(pathPrefix);
}
//字符串分割成字符数组
return pathPrefixes.toArray(new String[pathPrefixes.size()]);
}
这个parse主要是把每个包分离出来,然后把.换成/,再把每个包保存到一个字符数组中。
四、实例化一个prepareOperations对象
public PrepareOperations(ServletContext servletContext, Dispatcher dispatcher) {
this.dispatcher = dispatcher;
this.servletContext = servletContext;
}
这个prepareOperations对象主要是用来处理action请求的,如建立url和执行方法映射啊,参数处理啊 ,动态方法处理啊之类的,后面介绍struct2处理请求时再做介绍,这里主要讲初始化;
五,实例化一个excuteOperations对象
public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {
this.dispatcher = dispatcher;
this.servletContext = servletContext;
}
这个excuteOperations对象主要是用来执行action请求的,注意和上面处理的区别,一个是执行,一个是处理.调用拦截器,执行目标方法,处理result的方法都包装在这个类中。
六、处理黑名单
对于url的黑名单,我们可以在struct2.xml中配置"struts.action.excludePattern",参数填上你要禁止访问的url(这个是正则表达式)。这里主要是把配置的参数放到一个list中,以便在后面处理action的时候,用作判断,看是否在这个集合中。
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中,应为配置时是用正规表达式,所以用到了Pattern对象
list.add(Pattern.compile(token.trim()));
}
return Collections.unmodifiableList(list);
} else {
return null;
}
}
struct2初始化的工作上面基本已经介绍完了。现在总结一下,struct2初始化工作主要是解析配置文件,把配置信息封装到Dispacher对象中,然后初始化两个以后处理action请求的对象(prepareOperation和excuteOperation),然后把静态资源的路径放到一个字符数组,把黑名单放到一个list中,方便处理action请求时做判断。
下篇博文将介绍该博文遗留下来的问题-解析配置文件。
转载于:https://blog.51cto.com/yoyanda/1709636