论坛首页 Java企业应用论坛

仿造的acegi threadlocal

浏览 3176 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-07-17  
用过acegi的都知道acegi的用户登陆信息(用户id 角色)等放在threadLocal中
下面是自己土制的threadLocal 比acegi的简单很多,更容易明白它的原理
用过OpenSessionInView的就不用看了,原理完全一样
下面给出关键代码
//安全上下文,保存用户登陆数据
public class SecurityContext {
	public final static String SECURITY_CONTEXT_KEY = "cn.lottery.sale.security.securityContext";
	private Long userId;
	private String username;
	private List<String> roles = new ArrayList<String>();
}

LoginAction中的login方法
	public String login(){
		SecurityContext sc = new SecurityContext();
		sc.setUsername(username);
		getRequest().getSession().setAttribute(SecurityContext.SECURITY_CONTEXT_KEY, sc);
		return SUCCESS;
	}


//安全过滤器。绑定session中用户信息到threadLocal
public class SecurityFilter implements Filter {
	private final static Logger logger = LoggerFactory.getLogger(SecurityFilter.class);
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		HttpServletRequest req = (HttpServletRequest)request;
		HttpSession session = req.getSession();
		
		if(session != null){
			SecurityContext context = (SecurityContext)session.getAttribute(SecurityContext.SECURITY_CONTEXT_KEY);
			logger.debug("绑定用户信息到线程" + Thread.currentThread().getId());
			SecurityContextHolder.set(context);
		}
		try{
			chain.doFilter(request, response);
		}finally{
			logger.debug("删除绑定到当前线程的用户信息" + Thread.currentThread().getId());
			SecurityContextHolder.remove();
		}
		
	}
}


//逻辑类
public class LotteryManager {
	private final static Logger logger = LoggerFactory.getLogger(LotteryManager.class);
	private LotteryDAO lotteryDAO;
	
	@Transactional(readOnly = true)
	public List<Lottery> findLotteryByName(String lotteryName){
		logger.debug( SecurityContextHolder.get().getUsername() ); //看这儿啦 获取用户名。省去传递参数哪么麻烦
		return lotteryDAO.findByProperty("shortName", lotteryName);
	}
	
}
   发表时间:2008-07-20  
ThreadLocal存放登陆人员信息?有两个问题

1、既然都在session里了,为什么不直接就从session里取出来用,还要在次放到ThreadLocal中??难道就是为了能在没有request的地方使用而不需要把其当成参数传进来????

2、ThreadLocal是哪个Thread的ThreadLocal??如果Thread结束,则ThreadLocal也跟着销毁?再多个线程之间共享登陆信息的话,那也就是说必须保证给每一个登陆用户创建一个始终处于运行状态的线程?怎么保证的?
0 请登录后投票
   发表时间:2009-01-26  
楼上的朋友别激动,之所以这么做,正是为了可以在各个层次中,包括serice,dao甚至model类中直接把登陆的User对象取出来应用,而不必为了获得session而伤脑筋 。 不只是登陆用户,所有具有这种需求的对象都可以这么做。
ThreadLocal在这种需求中往往定义成static的, 它会为每个线程单独创建一个类似Map的东西,Map的key就是当前线程对象,value就是要保存的对象。 所以每个线程都可以获得自己的对象,ThreadLocal永远不会销毁。
但web container不能保证每个request到来时都分配同样的线程,所以需要一个filter来拦截这个request,把分配给它的那个线程赋予相应的对象
0 请登录后投票
   发表时间:2009-03-05  
wanghualeilei 写道
楼上的朋友别激动,之所以这么做,正是为了可以在各个层次中,包括serice,dao甚至model类中直接把登陆的User对象取出来应用,而不必为了获得session而伤脑筋 。 不只是登陆用户,所有具有这种需求的对象都可以这么做。
ThreadLocal在这种需求中往往定义成static的, 它会为每个线程单独创建一个类似Map的东西,Map的key就是当前线程对象,value就是要保存的对象。 所以每个线程都可以获得自己的对象,ThreadLocal永远不会销毁。
但web container不能保证每个request到来时都分配同样的线程,所以需要一个filter来拦截这个request,把分配给它的那个线程赋予相应的对象


不错,每个Thread单独创建一个类似Map的东西,它就是threadLocals,是ThreadLocal.ThreadLocalMap的一个实例,
ThreadLocalMap是ThreadLocal的静态内部类,他的key是this,即:当前的ThreadLocal实例,而非当前的Thread实例;
试想:在一次线程生命周期内,假如Class A中有一ThreadLocal“存储”信息X, Class B中有一ThreadLocal“存储”信息Y,假如往Thread的threadLocals放置变量副本,都以当前的Thread实例做Map的Key,岂不是会产生值覆盖问题?



0 请登录后投票
   发表时间:2009-03-05  
兄弟, 有个问题, 你要在合理的位置释放用户对象。 而且好处理好302/301跳转, 异常的抓取等等, 小心啊, 曾经我是犯过大错误。
0 请登录后投票
   发表时间:2009-03-05  
wanghualeilei 写道
楼上的朋友别激动,之所以这么做,正是为了可以在各个层次中,包括serice,dao甚至model类中直接把登陆的User对象取出来应用,而不必为了获得session而伤脑筋 。 不只是登陆用户,所有具有这种需求的对象都可以这么做。
ThreadLocal在这种需求中往往定义成static的, 它会为每个线程单独创建一个类似Map的东西,Map的key就是当前线程对象,value就是要保存的对象。 所以每个线程都可以获得自己的对象,ThreadLocal永远不会销毁。
但web container不能保证每个request到来时都分配同样的线程,所以需要一个filter来拦截这个request,把分配给它的那个线程赋予相应的对象

把ThreadLocal的原理搞清楚了再用,OK?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics