场景如下:在java后台处理业务的时候,需要调用当前登录用户的一些信息,一般情况下的做法是,在登录的时候,把登录对象放到HttpSession对象中,在需要调用的时候,从request或者session对象中获取,但是这种方式直适用于servlet或者action中调用,只有此处才能获取到request或session对象。如果需要在一个被调用的业务类中获取,则无法行得通。
分析:其实只需要找到一种可以讲request对象缓存,同时又可以在业务类中获取,即可解决上述问题。面对此问题,我参考了下OSCHINA的源码,http://www.oschina.net/code/snippet_12_2 ,其中很关键的一段代码如下:
private final static ThreadLocal<RequestContext> contexts = new ThreadLocal<RequestContext>();
而这个ThreadLocal类究竟是干什么用的呢,看下面这篇文章:
http://www.iteye.com/topic/103804
文章内容将的很清楚,关于ThreadLocal的用法,甚至举了hibernate中session管理的例子,咋一看,确实很容易搞晕,但是从下面的有一个回复内容,可以很清晰的明白这个类能干嘛:
或者可以自己定义一个静态的map,将当前thread作为key,创建的session作为值,put到map中,应该也行,这也是一般人的想法,但事实上,ThreadLocal的实现刚好相反,它是在每个线程中有一个map,而将ThreadLocal实例作为key,这样每个map中的项数很少,而且当线程销毁时相应的东西也一起销毁了,不知道除了这些还有什么其他的好处。
主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式
下面是我参考OSCHINA的ThreadLocal做的一个实例,供参考:
RequestContext类:
package com.xmf.demo.thread; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class RequestContext { private ServletContext context; private HttpSession session; private HttpServletRequest request; private HttpServletResponse response; private Map<String, Cookie> cookies; private final static ThreadLocal<RequestContext> contexts = new ThreadLocal<RequestContext>(); /** * 初始化请求上下文 * @param ctx * @param req * @param res */ public static RequestContext begin(ServletContext ctx, HttpServletRequest req, HttpServletResponse res) { RequestContext rc = new RequestContext(); rc.context = ctx; rc.request = req; rc.response = res; rc.session = req.getSession(false); rc.cookies = new HashMap<String, Cookie>(); Cookie[] cookies = req.getCookies(); if(cookies != null) for(Cookie ck : cookies) { rc.cookies.put(ck.getName(), ck); } contexts.set(rc); return rc; } /** * 获取当前请求的上下文 * @return */ public static RequestContext get(){ return contexts.get(); } public void end() { this.context = null; this.request = null; this.response = null; this.session = null; this.cookies = null; contexts.remove(); } public ServletContext getContext() { return context; } public void setContext(ServletContext context) { this.context = context; } public HttpSession getSession() { return session; } public void setSession(HttpSession session) { this.session = session; } public HttpServletRequest getRequest() { return request; } public void setRequest(HttpServletRequest request) { this.request = request; } public HttpServletResponse getResponse() { return response; } public void setResponse(HttpServletResponse response) { this.response = response; } public Map<String, Cookie> getCookies() { return cookies; } public void setCookies(Map<String, Cookie> cookies) { this.cookies = cookies; } }
此处是过滤器GlobalFilter的代码:
package com.xmf.base.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.xmf.demo.thread.RequestContext; /** * 全局过滤器 */ public class GlobalFilter implements Filter { private ServletContext context; /** * Default constructor. */ public GlobalFilter() { // TODO Auto-generated constructor stub } /** * @see Filter#destroy() */ public void destroy() { RequestContext.get().end();//清除线程变量值 } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest)request; HttpServletResponse res = (HttpServletResponse)response; RequestContext.begin(this.context, req, res);//初始化线程变量值 chain.doFilter(request, response); } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { } }
下面是servlet类
package com.xmf.demo.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.xmf.demo.test.Test; import com.xmf.demo.thread.RequestContext; /** * Servlet implementation class Request1Servlet */ public class Request1Servlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Request1Servlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestContext.begin(this.getServletContext(), request, response); Test test = new Test(); System.out.println(test.getPara()); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } }
最后是业务类:
package com.xmf.demo.test; import com.xmf.demo.thread.RequestContext; /** * 测试业务类 * @author gongstring * @date 2014年6月9日 下午5:40:20 */ public class Test { /** * <p>获取URL请求中的参数值,如果可以获取,则实现在业务类中获取request对象的需求</p> * @author gongstring * @date 2014年6月9日 下午5:43:11 * @return */ public static String getPara(){ return RequestContext.get().getRequest().getParameter("test"); } }
浏览器实例:http://127.0.0.1:8080/demo/rq1?test=ThreadLocalDemo