本帖最后由 王超举 于 2017-7-31 15:01 编辑
ThreadLocal,本身是一个工具类,用于往当前线程中存取一些数据。他内部调用ThreadLocalMap,一个map集合。其key是ThreadLocal这个工具类的引用,value是我们要往里面保存的值。 如果一个线程需要调用很多个方法,各个方法之间调用会显示的传参,如果要增加参数则需要该方法的参数列表,如果是用ThreadLocal来自定义一个工具类则不需要。
我们在java的三层框架调用时,如果dao层需要一个数据,一般是从service层传递过来的。如果代码已经写完,并且dao层要修改的方法有很多,这样做就太麻烦了,而且也使得代码有了侵入性。
这时候我们就可以写一个工具类,在工具类中定义一个ThreadLocal类型的变量,将需要传递给dao层,或者service层这样的数据保存在ThreadLocalMap里。在service层或dao层中从工具类中获取。
当然不仅仅这些操作普通的操作,在面向切面编程时同样会用到。下面看一个具体的案例。
需求:
在一个项目中,需要对dao层所有的save方法,增加权限校验,如果当前用户是管理员,则允许保存操作,否则不允许。项目简介:在servlet层、service层中调用下一层的对象,都是通过配置文件+工厂模式+反射生成的。
解决思路:
1、编写MyThreadLocalUtils.java类,用于在当前线程中保存已登陆的用户
[Java] 纯文本查看 复制代码 public class MyThreadLocalUtils {
private static final ThreadLocal<User> tl = new ThreadLocal<User>();
public static User getUser(){
User conn = tl.get();
return conn;
}
public static void setUser(User user){
tl.set(user);
}
}
2、在权限过滤的filter类中,调用MyThreadLocalUtils类,存储已登陆用户。ps:代码第20行。
[Java] 纯文本查看 复制代码 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
User user = (User) req.getSession().getAttribute("existUser");
StringBuffer url = req.getRequestURL();
String contextPath = req.getContextPath();
String[] split = url.toString().split(contextPath);
String[] urls = {"/jsp/order_list.jsp","/jsp/order_info.jsp",
"/OrderServlet","/CartServlet",
"/jsp/cart.jsp"};
boolean flag = false;
for (String string : urls) {
flag = split[1].startsWith(string);
if(flag && user == null ){
req.setAttribute("msg", "您还没登录,请先登录");
req.getRequestDispatcher("/jsp/msg.jsp").forward(req, resp);
return;
}
}
//往当前线程中存已登陆用户
User exitUser = (User) req.getSession().getAttribute("existUser");
MyThreadLocalUtils.setObject(exitUser);
chain.doFilter(request, response);
}
3、在beanFactory工厂类中,对dao层的save方法进行改造,调用MyThreadLocalUtils类,获取登陆的用户。ps:代码第38行。
3.1、获取到则执行保存操作
3.2、获取不到,不再调用目标的save方法,直接返回null。
[Java] 纯文本查看 复制代码
public class BeanFactory {
public static Object getBean(String objId){
try {
//读取配置文件
SAXReader saxReader = new SAXReader();
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.xml");
Document document = saxReader.read(in);
//获取配置文件中的对应的class属性值
Element ele = (Element) document.selectSingleNode("//bean[@id='"+objId+"']");
//根据class属性值获取创建对象
String classPath = ele.attributeValue("class");
Class clazz = Class.forName(classPath);
final Object obj = clazz.newInstance();
ClassLoader classLoader = obj.getClass().getClassLoader();
Class<?>[] interfaces = obj.getClass().getInterfaces();
MyInvocationHandler mih = new MyInvocationHandler(obj);
if(objId.endsWith("Dao")){
Object proxyInstance = Proxy.newProxyInstance(classLoader,interfaces,mih );
return proxyInstance;
}
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;
public MyInvocationHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().startsWith("save")){
System.out.println("权限校验=================");
//从ThreadLocal中获取User对象
User user = MyThreadLocalUtils.getUser();
if(user.getType() == 1){//管理员,可以执行保存操作
Object object = method.invoke(obj, args);
System.out.println("管理员,可以执行保存操作****************************");
return object;
}else{//普通用户,不可以执行保存操作
System.out.println("普通用户,不可以执行保存操作=================");
return null;
}
}
Object object = method.invoke(obj, args);
return object;
}
}
|