Struts2原理及源码分析

来源:互联网 发布:淘宝网秋冬男式上衣 编辑:程序博客网 时间:2024/05/22 01:57
  • struts介绍
    strtus2是WebWork的升级版,是一个运行稳定、性能优异、设计成熟的web框架,而struts则实现了MVC思想中的controller模块,而控制器实际上是由两部分组成,即拦截所有用户的请求,处理请求的通用代码都是由核心控制器完成的。在struts框架下,用户请求不再向JSP页面发送,而是由控制器StrutsPrepareAndExceptionFilter来将请求forword到指定JSP页面生成响应。

  • struts原理流程

    • 客户端初始化一个指向Servlet容器的请求
    • 这个请求经过一个系列的过滤器
    • StrutsPrepareAndExcuteFilter被调用,它会询问ActionMapper来决定这个请求调用某个Action
    • ActionMapper决定调用那个action,FilterDispatcher把请求的处理交给ASctionProxy
    • ActionProxy通过调用Configuration Manager询问框架的配置文件,找到需要调用的Action类
    • 创建ActionInvocation的实例
    • ActionInvocation实例使用命名模式来调用,在调用Acion的过程前后都会涉及到相关的拦截器(intercepter)的调用
    • 一旦action执行完毕,ActionInvocation负责根据struts.xml的配置找到相应的返回对应的返回结果,这个结果是一个需要被表示的JSP
  • FilterDispatcher

    • struts的核心过滤器,负责处理最初的请求
    • 四大责任:
      • 执行action:判断是否需要执行action,需要执行则该action则应该放在核心过滤器的最前面
      • 清空actionContext上下文:自动清理,确保没有内存泄露
      • 服务静态的内容:加载常用的javascript文件
      • 中断请求生命周期中的XWORKS拦截器
  • ActionMapper

    • 用来负责在Http请求和action调用之间进行一个映射
    • 为了帮助处理按钮和其他相关的需求,这个mapper(我们希望,其他ActionMapper也能这样)具有这样的功能:使用一些预定义的前缀命名一个按钮,这些按钮会引发执行行为.这四个前缀是:
      Method 前缀- method:default
      Action 前缀- action:dashboard
      Redirect 前缀- redirect:cancel.jsp
      Redirect-action 前缀- redirect-action:cancel

      除了这四个前缀,这个mapper也明白 foo!bar的action命名方式,或者扩展方式(例如 foo!bar.action) ,或者前缀方式(例如 action:foo!bar).这个语法告诉mapper映射到名称为foo的action和对应的方法bar.实现自己的ActionMapper,通过method参数将请求转发到具体的action,需继承DefaultActionMapper
  • ActionProxy&ActionInvocation

    • Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。
  • ConfigurationProvider&Configuration

    • ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析。
  • trutsPrepareAndExecuteFilter中的方法:

    • void init(FilterConfig filterConfig) 继承自Filter,过滤器的初始化
    • doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 继承自Filter,执行过滤器
    • void destroy() 继承自Filter,用于资源释放
    • void postInit(Dispatcher dispatcher, FilterConfig filterConfig) Callback for post initialization(一个空的方法,用于方法回调初始化)

web容器一启动,就会初始化核心过滤器StrutsPrepareAndExecuteFilter,并执行初始化方法,初始化方法如下:

复制代码
1 public void init(FilterConfig filterConfig) throws ServletException {
2 InitOperations init = new InitOperations();
3 Dispatcher dispatcher = null;
4 try {
5 //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中
6 FilterHostConfig config = new FilterHostConfig(filterConfig);
7 //初始化struts内部日志
8 init.initLogging(config);
9 //创建dispatcher ,并初始化
10 dispatcher = init.initDispatcher(config);
11 init.initStaticContentLoader(config, dispatcher);
12 //初始化类属性:prepare 、execute
13 prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
14 execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
15 this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
16 //回调空的postInit方法
17 postInit(dispatcher, filterConfig);
18 } finally {
19 if (dispatcher != null) {
20 dispatcher.cleanUpAfterInit();
21 }
22 init.cleanup();
23 }
24 }
复制代码
关于封装filterConfig,首先看下FilterHostConfig ,源码如下:

复制代码
1 public class FilterHostConfig implements HostConfig {
2
3 private FilterConfig config;
4 //构造方法
5 public FilterHostConfig(FilterConfig config) {
6 this.config = config;
7 }
8 //根据init-param配置的param-name获取param-value的值
9 public String getInitParameter(String key) {
10 return config.getInitParameter(key);
11 }
12 //返回初始化参数名的迭代器
13 public Iterator getInitParameterNames() {
14 return MakeIterator.convert(config.getInitParameterNames());
15 }
16 //返回Servlet上下文
17 public ServletContext getServletContext() {
18 return config.getServletContext();
19 }
20 }
复制代码
  只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。

  接下来,看下StrutsPrepareAndExecuteFilter中init方法中dispatcher = init.initDispatcher(config);这是初始化dispatcher的,是通过init对象的initDispatcher方法来初始化的,init是InitOperations类的对象,我们看看InitOperations中initDispatcher方法:

1 public Dispatcher initDispatcher( HostConfig filterConfig ) {
2 Dispatcher dispatcher = createDispatcher(filterConfig);
3 dispatcher.init();
4 return dispatcher;
5 }
  创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :

复制代码
1 private Dispatcher createDispatcher( HostConfig filterConfig ) {
2 //存放参数的Map
3 Map

0 0