Struts2

Struts2

特性

Servlet是单例的,多个程序访问同一个Servelt只会创建一个Servlet实例.Action是多例的,一次请求就创建一个实例,故在Action中创建成员变量不会出现线程安全.

系统架构

在这里插入图片描述

  • FilterDispatcher:整个Struts2的调度中心根据ActionMapper的结果来决定是否处理请求,如果ActionMapper指出该URL应该被Struts2处理,那么它将会执行Action处理,并停止过滤器链上还没有执行的过滤器。
  • ActionMapper:判断这个请求是否应该被Struts2处理,如果需要Struts2处理,ActionMapper会返回一个对象来描述请求对应的ActionInvocation的信息。
  • ActionProxy:创建一个ActionInvocation实例,位于Action和xwork之间,使得我们在将来有机会引入更多的实现方式,比如通过WebService来实现等。
  • ConfigurationManager:xwork配置的管理中心,可以把它看做struts.xml这个配置文件在内存中的对应。
  • struts.xml:是Stuts2的应用配置文件,负责诸如URL与Action之间映射关系的配置、以及执行后页面跳转的Result配置等。
  • ActionInvocation:真正调用并执行Action,它拥有一个Action实例和这个Action所依赖的拦截器实例。ActionInvocation会按照指定的顺序去执行这些拦截器、Action以及相应的Result。
  • Interceptor (拦截器):是Struts2的基石,类似于JavaWeb的Filter,拦截器是一些无状态的类**,拦截器可以自动拦截Action**,它们给开发者提供了在Action运行之前或Result运行之后来执行一些功能代码的机会。
  • Action:用来处理请求,封装数据。

初始化

Struts2框架初始化搭建运行环境,这是为驱动框架核心功能的准备工作.

public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
    private static final Logger LOG = LogManager.getLogger(StrutsPrepareAndExecuteFilter.class);
    // Http 预处理类
    protected PrepareOperations prepare;
    // Http 处理执行类
    protected ExecuteOperations execute;
    // 不进行处理的Url
    protected List<Pattern> excludedPatterns = null;

    public StrutsPrepareAndExecuteFilter() {
    }

    //  实现继承自父类 Filter 的init 方法
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化操作类
        InitOperations init = this.createInitOperations();
        Dispatcher dispatcher = null;

        try {
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            init.initLogging(config);
            //  初始化核心分发器 Dispatcher
            dispatcher = init.initDispatcher(config);
            //  静态资源加载器
            init.initStaticContentLoader(config, dispatcher);
            // 初始化预处理类以及执行类
            this.prepare = this.createPrepareOperations(dispatcher);
            this.execute = this.createExecuteOperations(dispatcher);
            this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
            this.postInit(dispatcher, filterConfig);
        } finally {
            if (dispatcher != null) {
                dispatcher.cleanUpAfterInit();
            }

            init.cleanup();
        }

    }
  1. 在init()方法中遍历从filterConfig 中获取参数集合,存放到Map中并最终封装成Dispatcher对象,其中filterConfig中的参数集合来自于web.xml文件中的初始化参数配置。
  2. 核心分发器Dispatcher 为主对各种元素进行转换
    • 配置元素的加载器,负责把配置元素转换成框架元素;
    • 配置元素的构造器,负责对框架元素进行初始化操作,使用构造模式;
    • 配置元素的管理类,负责管理和控制配置元素的初始化;
配置文件加载
  1. 核心控制器的实质是过滤器,Struts2中的过滤器会在服务器启动时创建。过滤器中的init();方法被调用;
  2. 过滤器中的init();被Dispatcher 加载,配置文件被调用,加载struts2中的所有配置文件;
public class Dispatcher {

    public void init() {
        if (this.configurationManager == null) {
            this.configurationManager = this.createConfigurationManager("default");
        }

        try {
            this.init_FileManager();
            this.init_DefaultProperties();            //  [1]
            this.init_TraditionalXmlConfigurations(); //  [2]
            this.init_LegacyStrutsProperties();       //  [3]
            this.init_CustomConfigurationProviders(); //  [5]
            this.init_FilterInitParameters();         //  [6]
            this.init_AliasStandardObjects();         //  [7]
            Container container = this.init_PreloadConfiguration();
            container.inject(this);
            this.init_CheckWebLogicWorkaround(container);
            if (!dispatcherListeners.isEmpty()) {
                Iterator i$ = dispatcherListeners.iterator();

                while(i$.hasNext()) {
                    DispatcherListener l = (DispatcherListener)i$.next();
                    l.dispatcherInitialized(this);
                }
            }

            this.errorHandler.init(this.servletContext);
        } catch (Exception var4) {
            LOG.error("Dispatcher initialization failed", var4);
            throw new StrutsException(var4);
        }
    }

}
  • init_DefaultProperties();——org/apache/struts2/default.properties这是struts2中定义的所有常量属性;

  • init_Traditiona;XmlConfigurations();——struts-default.xml(其中定义了拦截器以及需要继承的包),struts-plugin.xml(插件的配置文件),struts.xml;

    struts-default.xml默认栈的拦截器会依次执行,每个拦截器都有特有的功能.

    [外链图片转存中…(img-yhNMK4hX-1571817771585)]

    workflow拦截器:Strut2会提供一个数据存储的区域,其中有错误信息存储的区域.出现错误时将错误信息填装到错误信息区域.**其中最后一个拦截器会检查错误区域,**没有错误会跳转到Action页面,出现错误跳转到input页面视图.(配置input页面,将出错引向Error页面)

  • init_LegacyStrutsProperties();——加载struts.properties用户自定义的文件;

  • init_CustomConfigurationProiders();——加载配置提供类;

  • init_FilterInitParameters();——加载web.xml中过滤器初始化值;

  • init_AliasStandardObjects();——加载Bean对象

所以,文件加载顺序为:

在这里插入图片描述

但是,后配置的常量的值会覆盖先配置的常量的值

运行流程

  1. 用户发出请求
  2. 请求到达核心过滤器.StrutsPrepareAndExecuteFilter,该过滤器有俩个主要方法,init()doFilter()方法. (在Struts2.1以前调用FilterDispatcher,Struts2.1以后调用StrutsPrepareAndExecuteFilter )
    • init():开始执行初始化操作
    • doFilter():创建ActionContext(),包装request对象.AtionMapper通过FilterDispatcher对象创建一个Action的代理.
      • 初始化时会将Action中的name属性以及class属性绑定存储带一个map对象,ActionMapper会加载这个对象通过反射找到指定Action.
  3. 执行invocation.invoke()方法,即ActionInvocation.由此真正调用并执行Struts2.
    • 递归依次执行拦截器,直到结束调用Action;
    • Action会提供一个Result返回值,根据Result模板类型提供页面类型;
    • 递归逆序执行拦截器
  4. 到达页面做出相应,由Result给出response响应到页面.

拦截器.

​ 相较于Filter过滤器拦截从客户端发向服务器的请求,Interceptor拦截器拦截的时客户点对Action的访问,该拦截为更细粒化的拦截,可具体拦截到某一方法.

数据封装

访问servlet

​ seruts2于servlet是解耦合的,如果使用到servlet中的API对象,例如response、session,需要访问servlet的API有三个方法。

  • 完全解耦合的方式
  • 使用servelt的原生API方式
  • 接口注入方式
完全解耦合

方法:利用Struts2中的对象ActionContext.当请求过来时,执行过滤器方法中创建了ActionContext方法.即Action上下文.可以通过ActionContext方法获得值栈对象.

ActionContext context = ActionContext.getContext();
ActionContext方法作用
getParameters()接收参数
put(key,value)设置参数
getSession()获取session
getApplication()获取Application
getContext().getValueStack()获得值栈

这种方法只能获得代表request,session,application的数据的map集合,不能操作这些对象.

servelt的原生API

方法:通过ServletActionContext方法提供的的一些静态方法获得原生API.

ServletActionContext方法作用
getResponse()获得response对象
getrequest()获得request对象
getPagrContext()获得PagrContext对象

既可以操作域对象的数据,同时也可以获得域对象本身的方法

接口注入

实现ServletResquestAware,ServletContextAware接口,通过接口中提供的方法设置值

转发重定向

分俩种,全局配置全部执行,或是局部执行

  • 全局页面结果配置:

  • 局部页面结果配置:

    • type属性:

      • dispatcher:默认值,Action请求转发JSP;

      • redierct:Action重定向JSP;

      • chain:Action请求转发Action;

      • redirectAction:Action重定向Action;

      • stream:Struts2提供的文件下载

简单数据封装

前端页面发送的数据由后台获取.

属性驱动
方法一:提供set方法
  • 在页面添加类的各个属性
  • 为属性添加get,set方法
方法二:页面提供表达式
  • 在页面form传输的数据中为每一个属性加上类名

  • 在Action页面提供一个User对象,然后配置get(),set()方法.这是因为拦截器需要进行数据封装,使用

模型驱动
  • 实现模型驱动的接口ModelDriven
  • 实现一个Model()方法,返回一个实体类,手动提供一个成员变量实例对象

复杂数据封装

即前端一次性发送一组数据,将数据封装成数组发送

封装为List
  • 前端将发送的数据name属性设置为数组格式;
  • Action添加实例对象的List集合,以及对应的get,set方法;
封装为Map
  • 前端将发送的数据name属性设置为map[“key”]格式;
  • Action添加实例对象的map集合,以及对应的get,set方法;

值栈

struts2将Xwork对ognl扩展这一套机制封存起来,这个对象叫ValueStack.字面意思为值栈**.Struts2中使用OGNL将请求ACtion的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中独享属性值.**

  • ValueStack类似于一个数据中转站(Struts框架中的数据都保存到值栈中);
  • Action一旦创立,相应就创建一个ValueStack实例;
  • 一处保存可以在任何地方读取.

内部结构

ValueStack中俩快主要的区域:

  • root区域:其实就是一个ArrayList,里面一般放置对象;
    • 获取root区域数据不需要加#
  • context区域:其实就是一个Map.里面放置的是web开发过程中对象的引用.
    • 获取context区域数据需要加#
      • request
      • session
      • application
      • parameters
      • attr

获得值栈

通过ActionContext
  • 过滤器在接收请求时,创建ActionContext对象,期间建立对ValueStack的引用
ValueStack stack  = ActionContext.getContext().getValueStack();
通过request

创建Action代理将ValueStack放置到request中

ValueStack stack = (ValueStack)ActionContext.etRequest().getAttribute(ServletAction);

操作数据

存储数据
通过Action中的get()

此方法是利用Action本身在值栈中的特性.在默认情况下,将Action对象压入到值栈中,Action中的属性也随之压入,提供一个get()方法让值栈提取值.

调用ValueStack方法

push(Object obj);

set(String key,Object obj);

手动使用方法将对象压入栈顶位置.

获取数据
通过ognl的方式
  • root:不需要使用#
  • context:使用#
通过el表达式

容器学习

	在框架中,容器被设计为在系统初始化时就进行自身的初始化,并且能够在系统全局任何编程层次中进行访问的对象。通过它可以做到对对象的创建以及引用,对象以及本身子的依赖处理。

在这里插入图片描述

  • 核心分发器 Dispatcher : Dispatcher 不属于XWork框架的组成,但是是XWork框架的调用者和驱动执行者,在运行过程中起着重要的作用。

  • 控制流体系 (ActionProxy, ActionInvocation, Inteceptor, Action, Result)

    • Interceptor和Action以及Result作为事件处理节点,是处理事件逻辑的主要地方;
    • ActionProxy和ActionInvocation负责对这些事件处理节点进行调用;
      • 这里,ActionProxy主要是XWork框架和外部环境,为框架内部元素提供一个环境的同时也提供外部调用XWork内部元素的接口,即负责提供一个执行环境。
      • ActionInvocation作为核心调度器,主要负责的就是对事件处理节点进行调用。
  • 数据流体系 (ActionContext, ValueStack)ActionContext负责数据的储存和数据的共享

    ,ValueStack 在ActionContext的基础之上,负责数据的操作。

    • ValueStack是ActionContext的内部对象 ;
    • ActionContext中封装了许多对框架内部对象的访问接口 ;
    • ActionContext中封装了许多对框架内部对象的访问接口,主要分成两种
      • 对XWork框架对象的访问,getContainer,getValueStack,getActionInvocation;
      • 对数据对象的访问, getSession,getApplication,getParameters等 ;

当connecter传递来包装后的请求进入Xwork容器

功能

对象创建以及依赖注入有俩大功能: 对象创建以及依赖注入

创建对象
public interface Container extends Serializable {
    String DEFAULT_NAME = "default"/*处理对象依赖
    *	作用:建立起任意对象到框架元素沟通的桥梁
    *	入参:被注入依赖的对象
    * 	实现
    *		1.扫描传入的对象中声明有 @Inject 注解的字段,方法,构造函数,方法参数.
    *		2.将它们注入容器托管对象,实现任意对象与容器对象之间的关系。
    */
    void inject(Object var1);
    <T> T inject(Class<T> var1);
    
	/*获得对象实例 
     * 	获取范围:
     *  	1.声明在XML文件中的 <bean> 标签(包括框架内部bean以及自定义的bean)
     *		2.<constant> 标签
     */
    <T> T getInstance(Class<T> var1, String var2);
    <T> T getInstance(Class<T> var1);
	
	//对一个接口的多个不同实现类之间的实例获取的管理
    Set<String> getInstanceNames(Class<?> var1);
	
	//处理对象作用范围
    void setScopeStrategy(Strategy var1);
    void removeScopeStrategy();
}
在Container实现类中包含俩个主要的数据结构 Map, factories. 由构造函数发现, factoryNamesByType 是通过遍历 factories 得到的。 factories  即 InternalFactory<?>,factories 由此获得key值
class Key<T> {
    final Class<T> type;
   /*
  	*	key是由name以及hashCode构成
    *	对应<bean> 标签中声明的 name 和 type 属性
    */
    final String name;
    final int hashCode;
    
    private Key(Class<T> type, String name) {
        if(type == null) {
            throw new NullPointerException("Type is null.");
        } else if(name == null) {
            throw new NullPointerException("Name is null.");
        } else {
            this.type = type;
            this.name = name;
            this.hashCode = type.hashCode() * 31 + name.hashCode();
        }
    }
    Class<T> getType() {
        return this.type;
    }
    String getName() {
        return this.name;
    }
    public int hashCode() {
        return this.hashCode;
    }
    public boolean equals(Object o) {
        if(!(o instanceof Key)) {
            return false;
        } else if(o == this) {
            return true;
        } else {
            Key other = (Key)o;
            return this.name.equals(other.name) && this.type.equals(other.type);
        }
    }
    public String toString() {
        return "[type=" + this.type.getName() + ", name='" + this.name + "']";
    }
    static <T> Key<T> newInstance(Class<T> type, String name) {
        return new Key(type, name);
    }
}

而InternalFactory 只是定义了一个方法的接口,声明了对象的创建方法, 得知 factories 中存储的是对象的实例构建方法。

interface InternalFactory<T> extends Serializable {
    /*
    * @param  context of this injection
    * 
    * @return instance to be injected
    */  
    T create(InternalContext var1);
}
依赖注入

在容器实现类ContainerImpl 中,**利用Map存储对象以及对象之间的依赖关系. **通过扫描对象中具有 @Inject 注解的字段或方法,通过该标志初始化相应的注入器,放入到 ContainerImpl 中的 ReferenceCache 类型中的 injectors 中,供之后的对象依赖注入使用。 @Inject 注解在框架内部作为一个标志,被转换成不同的 Injectot 对象, 从而实施依赖注入。

本章借鉴于 https://www.cnblogs.com/forwrader/p/7659708.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值