论坛首页 Java企业应用论坛

Spring Singleton的陷阱

浏览 26895 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-12-24  
回复内容同daquan198163.

不过我常用的是一个专门的类.例如UserHelper之类.在其中利用ThreadLocal 存放User信息.然后用静态方法获得用户示例.

在Service里面声明一个field不是一个好的方法.原因就是标题写的Singleton.
0 请登录后投票
   发表时间:2006-12-24  
请注意楼主对问题的描述,
如前面兄弟所说,再acegi基础上再搞threadlocal...?
0 请登录后投票
   发表时间:2006-12-24  
象楼主这样写肯定出错呀,大家都用一个service对象,你又把user设置为它的全局变量,而且还这样写:private UserInfo user = super.getUserInfo();   ,大错特错,第一,spring管理的单列模式的bean中的全局变量应该是无状态的(这一点无论哪个文档上都有写吧,看来楼主对spring不是很熟,user明显是有状态的怎么能用作全局变量呢,肯定要把super.getUserInfo()放在service具体的方法里),第二看到楼上很多人不知道在说什么,不知所芸,有人说“可以修改配置文件,修改参数吧!!”,还有人说“改改配置,写个全局变量,什么问题也就解决了,哪有这么麻烦”,还有人说用ThreadLocal,acegi这种得到用户的方式本来就是ThreadLocal,还需要再用一个ThreadLocal吗??其实关键不在ThreadLocal这个地方。上面有个兄弟说得其实很清楚明白,只是我看大家都没有理解,flyspider说道:
引用
Spring建议以singleton方式注入的依赖尽量是stateless的

这才是正确的,只不过大家都没有明天他在说什么
0 请登录后投票
   发表时间:2006-12-24  
从注入角度讲,spring只是一个容器而已,怎么使用是一方面。
重要的是,从架构方面考虑,Service层是封装了对domain model的处理逻辑,是无状态的。
0 请登录后投票
   发表时间:2006-12-25  
Godlikeme 写道
这不是Spring 的问题,跟本问题要搞清楚,
public class SomeServece extends BaseService implements SomeInterFace    
{  
    private UserInfo user = super.getUserInfo();      
    public someMethod()  
    {  
       int userID = this.user.getUserID();  
       String userName = this.user.getUserName();  
       //bla bla do something user userID and userNaem  
    }  
}      

不能在service类里面写这种东西。居然有人说要用ThreadLocal...无语。


同意,这本身就是设计的问题,一般来说,service不应该保存状态
你的SomeServece好像也写错了
0 请登录后投票
   发表时间:2006-12-25  
ACEGI 感觉就是团MASS,虽然用了Spring。。。
0 请登录后投票
   发表时间:2006-12-25  
楼主不要发这种帖子来误导人了

service 被配置为 singleton, 就和 servlet 一样, 不允许有可写的成员变量, 这是 java 程序员的基本知识, Acegi SecurityContextHolder 默认采用 ThreadLocal 存储 authentication 对象, 每次使用当然都要重新获取, 在 singleton 的 service 成员变量中获取, 获取到的是第一次调用时得到的用户

顺便普及一下 SecurityContextHolder 的知识, SecurityContextHolder 中采用 SecurityContextHolderStrategy 来决定采用哪种策略存储 authentication 对象, 它有三个具体实现 :

1. GlobalSecurityContextHolderStrategy, 使用一个 static 变量存储 authentication 对象, 因此全局只有一个用户, 适合于 swing 的应用
2. ThreadLocalSecurityContextHolderStrategy, 采用 ThreadLocal 存储 authentication 对象, 它也是默认的实现
3. InheritableThreadLocal, 采用 InheritableThreadLocal 存储 authentication 对象

如果这种概念都没有搞清, 真让人怀疑你是怎么使用 spring 和 acegi 的

再来看一下 SecurityContextHolder 中如何选择 strategy
    private static void initialize() {
        if ((strategyName == null) || "".equals(strategyName)) {
            // Set default
            strategyName = MODE_THREADLOCAL;
        }

        if (strategyName.equals(MODE_THREADLOCAL)) {
            strategy = new ThreadLocalSecurityContextHolderStrategy();
        } else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
            strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
        } else if (strategyName.equals(MODE_GLOBAL)) {
            strategy = new GlobalSecurityContextHolderStrategy();
        } else {
            // Try to load a custom strategy
            try {
                if (customStrategy == null) {
                    Class clazz = Class.forName(strategyName);
                    customStrategy = clazz.getConstructor(new Class[] {});
                }

                strategy = (SecurityContextHolderStrategy) customStrategy.newInstance(new Object[] {});
            } catch (Exception ex) {
                ReflectionUtils.handleReflectionException(ex);
            }
        }
    }
0 请登录后投票
   发表时间:2006-12-25  
ACEGI我清楚,我在上面发的帖子你没看我已经写了为什么出错吗?
1:我是为了在Service层能够得到用户信息
2:不想从参数里传入用户信息
3:为了给继承类提供方便,所以我在BaseService里提供了方法
 protected UserContext getUserContext()  
 {  
     Authentication auth = SecurityContextHolder.getContext().getAuthentication();  
     return (UserContext) auth.getPrincipal();  
 }  

在基类中如果每次调用super.getUserContext()是肯定没问题的,因为这就是在调用ACEGI中ContextHolder中的方法,但是在继承类中保存了一个本地变量,当然会错了。这怎么是误导?
只不过对于某些程序员来说他并不知道Spring怎么处理,所以在继承类中写了一个本地变量来保存用户信息,而且在单元测试中也不会发现问题。

0 请登录后投票
   发表时间:2006-12-25  
Ivan Li 写道
ACEGI我清楚,我在上面发的帖子你没看我已经写了为什么出错吗?
1:我是为了在Service层能够得到用户信息
2:不想从参数里传入用户信息
3:为了给继承类提供方便,所以我在BaseService里提供了方法
 protected UserContext getUserContext()  
 {  
     Authentication auth = SecurityContextHolder.getContext().getAuthentication();  
     return (UserContext) auth.getPrincipal();  
 }  

在基类中如果每次调用super.getUserContext()是肯定没问题的,因为这就是在调用ACEGI中ContextHolder中的方法,但是在继承类中保存了一个本地变量,当然会错了。这怎么是误导?
只不过对于某些程序员来说他并不知道Spring怎么处理,所以在继承类中写了一个本地变量来保存用户信息,而且在单元测试中也不会发现问题。



呵呵, 我倒是觉得你所谓的 "某些程序员" 是被你误导才会这样做, 明明是对 Context 的获取, 竟然不是 static 的, 还做成 BaseService 的 protected 方法, 奇怪的用法
0 请登录后投票
   发表时间:2006-12-25  
这个就是个java基本概念不清楚的结果,其实和spring根本没什么关系。singleton在jvm里面只会有一个实例,lz的情况,属性变量在唯一实例产生的时候被赋值,以后当然不会改变了。
对于singleton的对象,还是stateless比较好点。
0 请登录后投票
论坛首页 Java企业应用版

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