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请求时做判断。
下篇博文将介绍该博文遗留下来的问题-解析配置文件。