1,说明整个Struts2的流程,越详细越好(10分)
初始化:
struts2是由过滤器驱动的:核心过滤器StrutsPrepareAndExecuteFilter在web应用启动的时候被服务器创建,并驻留服务器内存;
并调用init方法进行初始化;
过程包括:
核心过滤器的init方法主要做的事:
1 初始化配置文件;
配置文件默认解析顺序为
default.properties(struts默认的常量信息)--->struts-default.xml--->struts-plugin.xml--->struts.xml;
如果其中有相同信息则后者覆盖前者,因此我们要覆盖struts默认的常量最好是放在struts.xml中的constant元素中;
当然一些插件为了覆盖struts的默认常量也会在对应的struts-plugin.xml中定义常量;并最终汇总到struts.xml中;
2 初始化核心分发器:Dispatcher
Dispatcher dispatcher =init.initDispatcher(config);进行初始化,核心分发器Dispatcher在被创建的过程中
需要接收两个参数;newDispatcher(filterConfig.getServletContext(),params);和ServletContext;
dispatcher在初始化的时候做的事情:
a静态注入:将struts框架工作所需的对象创建并放入到容器中,这个容器的实现类是ContainerImpl
通过如下方法进行注值;
org.apache.struts2.config.BeanSelectionProvider.register(ContainerBuilder,LocatableProperties);
需要注入的是,这些值的注入都有一个特点:比如;
<beantype="com.opensymphony.xwork2.ActionProxyFactory"name="xwork"
class="com.opensymphony.xwork2.DefaultActionProxyFactory"/>
<beantype="com.opensymphony.xwork2.ActionProxyFactory"name="struts"
class="org.apache.struts2.impl.StrutsActionProxyFactory"/>
都有一个公共的接口:com.opensymphony.xwork2.ActionProxyFactory,并针对该接口有多个实现;struts内部肯定是通过接口
引用调用实现类的方法,这又是面向接口编程,大大提高了程序的扩展性;如果你要改写这些配置,
只要在你的struts.xml配置文件中进行配置,但是前提有一个你必须实现它的接口,并将type定义为该接口,将你的实现类
定义为class,并取和上面相同的名称,达到覆盖的效果;
3 初始化PrepareOperations:
他的作用
a:准备struts的执行环境,具体来说就是创建ActionContext;
b:对request进行包装;
c:action路径的寻址和过滤;
4 初始化ExecuteOperations
他的作用:
a:执行静态资源请求;
b:执行action;
struts2的执行流程;
1加载并解析配置文件,解析顺序为struts-default.xml,struts-plugin.xml,struts.xml;
如果这三个文件中有相同内容,则后者覆盖前者;配置文件加载后创建struts基本元素:即<beantype=*,class=*>
结果集合拦截器(只有被引用到的拦截器才会被创建,即interceptor-ref的)
需要注意的是<bean>节点对应的元素,type和class的关系,type:
是父类或者接口,而class是对应的实现类,我们说过配置文件是有加载顺序的,我们要覆盖struts的默认配置
可以在struts.xml,但是覆盖有一个前提,你的实现类,type必须和默认中的type相同;
实现类自己定义,因为在struts调用你的实现类是通过type对应的引用来调用的,实际上的实现类是由你提供的'
这是完全的面向接口(父类)编程,符合开闭原则;比如说
<beantype="com.opensymphony.xwork2.ObjectFactory" name="struts"
class="org.apache.struts2.impl.StrutsObjectFactory"/>这是struts中的默认配置,你要修改他的创建模式;
就必须和他继承相同的父类;比如spring集成struts的插件中的struts-plugin.xml配置文件的配置;
<bean type="com.opensymphony.xwork2.ObjectFactory"name="spring"
class="org.apache.struts2.spring.StrutsSpringObjectFactory"/>
在struts中一定有这么一行代码:
ObjectFactory objectFactory;并提供相应的set,get方法
然后在使用到的地方直接就是
objectFactory.buildBean();//至于这个buildBean怎么执行不管,但是你的实现类一定要有这个方法;
否则就会导致整个框架的混乱
开闭原则:
实现类你爱怎么实现怎么实现,这是开的一方面;
但是你必须得保证,我父类有的方法一定要有实现;
或者说我的buildBean一定要能执行;这是闭的一方面;
同时配置文件中的内容允许覆盖也正是体现了这点,如果你都不允许他人覆盖你的配置,把什么都写死了,三大框架整合就是
个笑话.
一句话:开闭原则就是对于扩展性我完全开放,但是对于我struts整个的执行流程,谁都不能动,这是我的根基;
拦截器的创建时机:
struts2拦截器的创建机制:只有使用到的拦截器才会被创建,这个很好理解,是为了内存消耗的考虑,你没事叫人过来干嘛,
叫过来,又叫人回去,啥事也不干,你不是有病吗?
将解析到的一个个interceptor-ref节点封装成InterceptorMapping,多个InterceptorMapping组成一个集合
List<InterceptorMapping>interceptors;多个集合构成一个
InterceptorStackConfig拦截器栈映射对象;
然后交给ObjectFactory统一创建,具体的是由StrutsObjectFactory进行创建;
protectedvoid loadInterceptorStacks(Element element, PackageConfig.Buildercontext) throws ConfigurationException {
//这句代码的意思是,看看配置文件中哪些拦截器栈被引用了,引用了,就进一步的追踪拦截器栈中的拦截器
NodeList interceptorStackList =element.getElementsByTagName_r("interceptor-stack");
for (int i = 0; i <interceptorStackList.getLength(); i++) {
Element interceptorStackElement = (Element)interceptorStackList.item(i);
InterceptorStackConfig config =loadInterceptorStack(interceptorStackElement, context);
context.addInterceptorStackConfig(config);
}
}
init的方法执行完成后,所有的对象都会跑到ContainerImpl这个容器中,这是struts2的核心容器;即IOC容器;
2当请求到来的时候,首先经过核心过滤器的doFilter方法;这个方法实现了以下功能;
a:初始化action执行环境,ActionContext;
对请求url进行解析,并判断你的url是否是需要经过struts的核心;
如果需要做进一步的处理,如果不需要执行chain.doFilter放行;
当然这一步是粗粒度的进行判断,接下来对请求进行包装,解析出对应的action;
并在ActionMapping中找看是否存在对应的action映射;
如果不存在,继续判断是否是要使用到struts的静态资源,即路径中有