xwork

ActionContext作为xwork的数据流实现的元素,作为一个数据载体,负责数据存储,又负责数据共享。

ValueStack是一个具备表达式引擎计算功能的数据结构。xwork将ValueStack置于ActionContext中目的为静态的数据添加计算功能。


xwork的执行栈:

Interceptor与Action之间形成了包裹的结构。把Action包在最里面,栈-----interceptor-stack,在整个站的结构中,除了位于栈底的Action外,其他元素都是Interceptor对象,当试图吧Action对象拿出来时,要先把其之上的所有Interceptor依次拿出来执行,位于栈中的interceptor,除了需要她完成自身的逻辑外,还需要指定下一步的执行对象。

从源码中,ActionContext真正的数据存储空间,位于内部的一个Map类型的变量context,ActionContext将所有的数据对象以特定的键值存储于context中,ActionContext页提供了存取这些对象的方式。

数据共享:线程安全问题。

线程安全的判断标准:进行数据共享的信息是类的内部实例变量,外部对内部数据的访问是否存在多线程环境。ActionContext都满足。。哈哈。

怎么办?源码里ActionContext内封装了静态的ThreadLocale的实例,而这静态的ThreadLocale本身所操作和存储的对象,又是ActionContext本身。所以保证ActionContext的实例都是线程安全的。使用ThreadLocale处理多线程问题,


ThreadLocal类在维护变量时,实际使用了当前线程(Thread)中的一个叫做ThreadLocalMap的独立副本,每个线程可以独立修改属于自己的副本而不会互相影响,从而隔离了线程和线程,避免了线程访问实例变量发生冲突的问题。

ThreadLocal本身并不是一个线程,而是通过操作当前线程(Thread)中的一个内部变量来达到与其他线程隔离的目的。之所以取名为ThreadLocal,所期望表达的含义是其操作的对象是线程(Thread)的一个本地变量。如果我们看一下Thread的源码实现,就会发现这一变量,如代码清单4-2所示:

public class Thread implements Runnable {
 // 这里省略了许多其他的代码
ThreadLocal.ThreadLocalMap threadLocals = null;
}


这是JDK中Thread源码的一部分,从中我们可以看出ThreadLocalMap跟随着当前的线程而存在。不同的线程Thread,拥有不同的ThreadLocalMap的本地实例变量,这也就是“副本”的含义。接下来我们再来看看ThreadLocal.ThreadLocalMap是如何定义的,以及ThreadLocal如何来操作它,如代码清单4-3所示:

public class ThreadLocal<T> {

// 这里省略了许多其他代码

// 将value的值保存于当前线程的本地变量中
public void set(T value) {
    // 获取当前线程
    Thread t = Thread.currentThread();
    // 调用getMap方法获得当前线程中的本地变量ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    // 如果ThreadLocalMap已存在,直接使用
    if (map != null)
         // 以当前的ThreadLocal的实例作为key,存储于当前线程的
         // ThreadLocalMap中,如果当前线程中被定义了多个不同的ThreadLocal
         // 的实例,则它们会作为不同key进行存储而不会互相干扰
         map.set(this, value);
    else
         // ThreadLocalMap不存在,则为当前线程创建一个新的
         createMap(t, value);
}

 // 获取当前线程中以当前ThreadLocal实例为key的变量值
public T get() {
    // 获取当前线程
    Thread t = Thread.currentThread();
    // 获取当前线程中的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 获取当前线程中以当前ThreadLocal实例为key的变量值
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
            return (T)e.value;
    }
    // 当map不存在时,设置初始值
    return setInitialValue();
}

// 从当前线程中获取与之对应的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

 // 创建当前线程中的ThreadLocalMap
void createMap(Thread t, T firstValue) {
    // 调用构造函数生成当前线程中的ThreadLocalMap
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

// ThreadLoaclMap的定义
static class ThreadLocalMap {
    // 这里省略了许多代码
}
}


从上述代码中,我们看到了ThreadLocal类的大致结构和进行ThreadLocalMap的操作。我们可以从中得出以下的结论:

1. ThreadLocalMap变量属于线程(Thread)的内部属性,不同的线程(Thread)拥有完全不同的ThreadLocalMap变量。

2. 线程(Thread)中的ThreadLocalMap变量的值是在ThreadLocal对象进行set或者get操作时创建的。

3. 在创建ThreadLocalMap之前,会首先检查当前线程(Thread)中的ThreadLocalMap变量是否已经存在,如果不存在则创建一个;如果已经存在,则使用当前线程(Thread)已创建的ThreadLocalMap。

4. 使用当前线程(Thread)的ThreadLocalMap的关键在于使用当前的ThreadLocal的实例作为key进行存储。


ThreadLocal模式,至少从两个方面完成了数据访问隔离,有了横向和纵向的两种不同的隔离方式,ThreadLocal模式就能真正地做到线程安全:

纵向隔离 —— 线程(Thread)与线程(Thread)之间的数据访问隔离。这一点由线程(Thread)的数据结构保证。因为每个线程(Thread)在进行对象访问时,访问的都是各自线程自己的ThreadLocalMap。

横向隔离 —— 同一个线程中,不同的ThreadLocal实例操作的对象之间的相互隔离。这一点由ThreadLocalMap在存储时,采用当前ThreadLocal的实例作为key来保证。

ThreadLocal模式并不是什么高深的学问,它甚至从JDK1.2开始就存在于Java世界中。由此可见,我们掌握一种知识的最终目的是熟练而合理地运用它。
ThreadLocal模式解决的是同一线程中隶属于不同开发层次的数据共享问题,而不是在不同的开发层次中进行数据传递。



Java代码 
// 代码清单1 SimpleThreadLocal  
class SimpleThreadLocal {  
    private MapvalueMap = Collections.synchronizedMap(new HashMap());  
    public voidset(Object newValue) {  
       valueMap.put(Thread.currentThread(), newValue);//①键为线程对象,值为本线程的变量副本  
    }  
    publicObject get() {  
       Thread currentThread = Thread.currentThread();  
       Object o = valueMap.get(currentThread);// ②返回本线程对应的变量  
       if (o == null &&!valueMap.containsKey(currentThread)) {// ③如果在Map中不存在,放到Map  
           // 中保存起来。  
           o = initialValue();  
           valueMap.put(currentThread, o);  
       }  
       return o;  
    }  
    public voidremove() {  
       valueMap.remove(Thread.currentThread());  
    }  
    publicObject initialValue() {  
       return null;  
    }  

两种不同的接口访问类型:

对xwork框架对象的访问-----getContainer  getValueStack  getActionInvocation

对数据对象的访问-----getSession、getApplication、getParameter

ActionContext所提供的数据对象的访问接口,返回的是Map类型的数据对象而与web容器无关。


ActionContex是xwork框架所定义的元素,而xwork框架本身是脱离web容器而单独存在的事件处理框架,因此ActionContext一旦引入web对象,势必与xwork解耦合的基本设计思想背离。

web原生对象与xwork封装后的对象的对应关系
web原生对象xwork封装后的对象
HttpServletRequestRequestMap
HttpSessionSessionMap
ServletContextAppliactionMap
xwork 封装过程的本质:被封装后的SessionMap对象,能进一步保证数据访问的线程安全性,保持所有存储对象的Map结构,可以统一数据访问格式。

可以通过调用ServletActionContext所暴露的接口完成对web原生容器的HttpServletRequest和HttpServletResponse的访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值