Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21641
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 132
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-22 00:16
文章分类

全部博文(14)

文章存档

2014年(14)

我的朋友

分类: Java

2014-04-22 00:21:47

一、应用场景

项目采用Spring框架进行设计:MVC+ACEGI+JDBC+AOP。

在项目需求中需要记录用户操作日志,通过Spring AOP设计一个完成日志记录的切面通知。

需要在切面通知中访问当前登录的用户信息,记录登录用户执行的相应操作。

那么,如何在切面通知中访问到当前登录的用户信息呢?有2种方式。


二、实现方式一:前提是在项目中使用了ACEGI框架。

因为用户在登录的时候需要通过Spring Security进行验证,并且验证成功之后会在session中保存用户信息,所以可以直接通过如下方式获取到当前会话的登录用户信息:

UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String user = userDetails.getUsername();


三、实现方式二:通过ThreadLocal来实现。

第一步:用户登录成功后将用户信息保存到session中。

第二步:用户在访问某个action时,从 session中取出用户信息,再保存到与当前线程关联ThreadLocal对象里。(应该是在访问action的filter中从session中取出用户信息保存到ThreadLocal对象中)。

第三步:在 访问某个action时,切面会被织入,由于切面通知与action一定是在一个相同的线程中执行的,并且在访问action时(或者在filter中) 已经将用户信息保存在了ThreadLocal中,所以在执行切面通知时就可以从这个ThreadLocal对象中取出用户信息了。这样就避免了在执行切 面时还要通过参数传递用户信息(这样的设计不好)。

分析:

(1)如果仔细分析一下Spring Security的实现源码,也是这个实现思路。

(2)之所以能够ThreadLocal对象在切面通知中访问到登录用户信息,是因为action和切面通知一定是在一个相同的线程中执行的。


四、ThreadLocal源码分析

// get()方法实现 public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t); // 在ThreadLocal中获取当前线程的threadLocals属性 if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
           return (T)e.value;
        }
    return setInitialValue();
}  
ThreadLocalMap getMap(Thread t) {
     return t.threadLocals;
} // set()方法实现 public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value); // 为当前线程赋值threadLocals属性 }

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

// ThreadLocalMap是ThreadLocal的内部类 ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue); // 显然,当前线程的threadlocal属性值一个以ThreadLocal对象为key,要存放的对象为value的map对象     size = 1;
    setThreshold(INITIAL_CAPACITY);
} 

通过分析ThreadLocal的set(T t)源码可以知道,ThreadLocal为Thread保存的变量值都是保存在线程对象自己的threadLocals属性中。关于ThreadLocal与Thread的关系可以用下图表示:



五、ThreadLocal应用总结

(1)可以通过ThreadLocal对象保存线程本地变量。

(2)ThreadLocal不能实现多线程间的数据共享,即ThreadLocal不能实现多线程同步。多线程同步只能通过synchronized,Lock,wait,notify等方式来实现。


参考博文:

http://www.blogjava.net/jspark/archive/2006/08/01/61165.html

http://blog.csdn.net/qjyong/article/details/2158097










阅读(440) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Java Web禁止浏览器缓存的终极之道

给主人留下些什么吧!~~