论坛首页 Java企业应用论坛

小试ThreadLocal想到“隐式参数”模式

浏览 8342 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (3) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-03-27  
最近同事想通过自定义函数来输出国际化文字。比如:
${my:i18n('login.userid')}.
EL支持我们自定义这样的函数,问题是这个函数没法获取request对象,不知道当前页面的语言。

由此我想到threadlocal也许可以解决这个问题。
我的思路是做一个filter,每次都把request引用保存在一个threadlocal变量里。然后在上述的i18n自定义函数里读取这个threadlocal变量,得到request。
代码如下:
1 定义一个类读写threadlocal变量

public class ThreadAttributes {

        private static ThreadLocal<Map<String, Object>> threadAttribues = new ThreadLocal<Map<String, Object>>() {

                protected synchronized Map<String, Object> initialValue() {
                        return new HashMap<String, Object>();
                }
        };

        public static Object getThreadAttribute(String name) {

                return threadAttribues.get().get(name);

        }

        public static Object setThreadAttribute(String name, Object value) {

                return threadAttribues.get().put(name, value);

        }

}

2 在一个filter里写入request
public void doFilter(ServletRequest req, ServletResponse resp,
                        FilterChain chain) throws IOException, ServletException {
                HttpServletRequest request = (HttpServletRequest) req;
                HttpServletResponse response = (HttpServletResponse) resp;

                
                ThreadAttributes.setThreadAttribute("request", req);
        .....
}

3 读取request
HttpServletRequest request = (HttpServletRequest)ThreadAttributes.getThreadAttribute("request");
                
                



由此,我想到其他类似的问题。
跟web相关的里的方法,往往都有request参数;
跟数据库相关的方法,往往都有连接或事务的参数;
跟绘图相关的方法里,往往有一个绘图设备参数;
。。。。
如今分层架构非常普及,如果这些非常令人讨厌,但又的确需要的参数,都用上述的方案来在堆栈之间传递,将是一个不错的主意。事实上,spring已经让我们尝到了甜头,解放了我们的DAO对象,看不到connection参数。

我这里且叫它为“隐式参数”模式。



   发表时间:2009-03-27  
兄弟,你的想法固然好,但是否考虑过度的使用,会造成架构层模型的破坏。

使用上是方便了,你可以在一个Thread的任何时候访问到request,但你也破坏的卸耦原则,使得你的很多Biz层甚至DAO层的类绑定了HttpServletRequest对象,也就绑定了Web服务这种模式。
0 请登录后投票
   发表时间:2009-03-27  
数据少了没有关系, 如果一个请求10M数据, 就玩完了. 需要你要在确保在适当的地方释放这些数据.
1 请登录后投票
   发表时间:2009-04-02  
Threadlocal使用不当很容易造成内存泄漏。 特别是在web环境中
0 请登录后投票
   发表时间:2009-04-02  
还得考虑中间件的线程池,释放不好的话ThreadLocal变量也不好维护。还不如i18n方法把Locale开放出来,由页面传进去

0 请登录后投票
   发表时间:2009-04-03  
我不知道各位对threadlocal的恐惧来自哪里,也许我是初生牛犊。

在struts2中,有2种方式获取request对象,一种是ioc即实现ServletRequestAware接口。
另一种就是HttpServletRequest request = ServletActionContext.getRequest ();

我曾奇怪,这个ServletActionContext怎么知道request对象是哪个?我看了手册,原来也是用threadlocal实现的。

http://www.opensymphony.com/webwork/api/com/opensymphony/xwork/ActionContext.html
官方文档 写道

The ActionContext is the context in which an Action is executed. Each context is basically a container of objects an action needs for execution like the session, parameters, locale, etc.

The ActionContext is thread local which means that values stored in the ActionContext are unique per thread. See the ThreadLocal class for more information. The benefit of this is you don't need to worry about a user specific action context, you just get it:

      ActionContext context = ActionContext.getContext();

Finally, because of the thread local usage you don't need to worry about making your actions thread safe.
0 请登录后投票
   发表时间:2009-04-03  
WEB国际化完全可以这样做,我上一个项目就是这样实现的,TOMcat最多也就是250个http线程(缺省80个)没问题。

不过没有像LZ一样把所有request保存下来,我们只是保存客户端的locale,似乎LZ有滥用嫌疑哈:)
0 请登录后投票
   发表时间:2009-04-03  
看起来,楼主有很强的“模式”发明欲
0 请登录后投票
   发表时间:2009-04-15  
sdh5724 写道
数据少了没有关系, 如果一个请求10M数据, 就玩完了. 需要你要在确保在适当的地方释放这些数据.


HttpServletRequest声明周期短,加上大多数请求都很短小精悍,因此我觉得对到过滤器的request对象判断一下contentType提出大容量的请求,然后再做ThreadLocal处理其实也不错.楼主看能不能顺着这个思路再优化一下
0 请登录后投票
   发表时间:2009-04-16  
楼主的探讨精神还是好的。加油。
没有同样的程序,只有不同的编程思想!!!
0 请登录后投票
论坛首页 Java企业应用版

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