【问题标题】:Working with scoped beans when the scope is optional?当范围是可选的时使用范围 bean?
【发布时间】:2014-04-07 15:52:29
【问题描述】:

当我需要一些 bean 时,我有一个有时不存在的范围。这本身不是问题。对于这些情况,我可以使用默认值。我的问题是自动装配。场景大致是这样的:

  1. 我有一个作用域 bean ICurrentLocale。它的作用域是User,作用域取决于用户当前是否登录。
  2. Autowire bean foo 包含一个字段 @Autowired ICurrentLocale currentLocale;
  3. foo上调用一些方法。
  4. 用户登录。现在,我有一个范围User
  5. foo上调用一些方法。

我的问题是,在第 5 点中,自动装配的 ICurrentLocale bean 仍然相同,尽管在用户范围内创建了一个新 bean。

是否有一种好的/简单/可理解的方法来构建一个 spring 配置,当在同一个线程中输入新范围时自动重新连接 bean?

或者我可以让 Spring “刷新”代理?

编辑这是我当前的范围实现:

@Override
public Object get( String name, final ObjectFactory<?> objectFactory ) {
    CurrentUserSession currentSession = userSessionFactory.getCurrentSession();
    if( currentSession == null ) {
        if( isLocaleProvider( name ) ) {
            return createLocaleProvider();
        }
        throw new BeanCreationException( "Could not create bean " + name + " the bean scope " + NAME + " can be used only after the user has signed in" );
    }

    Object bean = currentSession.getBean(name, objectFactory);
    return bean;
}

如您所见,只要没有用户登录,我就会创建一个虚拟 bean。如果我有会话,我会查看会话中的缓存。如果 bean 尚不存在,我使用 objectFactory 创建一个新的。

【问题讨论】:

  • 向我们展示您的UserScope 实现。
  • @SotiriosDelimanolis:给你。

标签: java spring configuration scope


【解决方案1】:

也许我误解了你的问题。

你的ICurrentLocale bean 应该是这样的

@Component
@Scope(value = "user", proxy-mode = "ScopedProxyMode.TARGET_CLASS")
public class CurrentLocaleImpl implements ICurrentLocale {
   ...
}

或对应的@Bean或XML配置。

通过这样的配置,Spring 将为您的注入目标创建一个代理。换句话说,在

@Autowired
private ICurrentLocale currentLocale;

你不会有一个CurrentLocaleImpl 对象,你会有一个代理对象,它引用了底层BeanFactory

5.在 foo 上调用一些方法。

我的问题是,在第 5 点中,自动装配的 ICurrentLocale bean 是 尽管在 用户范围。

当您调用代理 bean 上的方法时,代理将尝试使用您的 Scope 实现从 BeanFactory 检索实际的 CurrentLocaleImpl 对象,然后将方法调用委托给该对象。实际上,您将使用正确的对象、默认对象或引发异常。

【讨论】:

  • 我想我开始理解我的误解了。澄清一下:当 bean 被自动装配时,会注入一个代理,但那时,我的用户范围没有被调用 - bean 仍然是一个没有附加实例的代理。然后,当我在 bean 上调用第一个 method 时,就完成了代理查找。这是我范围内的get() 第一次被调用。这是正确的吗?
  • @Aaron 基本正确。在任何时候,注入的对象始终是代理(毕竟它是 Java,Spring 只处理一次 foo bean)。现在,每次您调用此对象的方法时,都会使用您的UserScope#get(..) 进行查找。您可以在此处缓存实际实例,也可以在每次调用时查找它。
  • 通过这个解释,我可以找到错误:一些帮助框架创建了一个新线程,当执行该线程中的代码时,userSessionFactory.getCurrentSession() 找不到会话... :-P
【解决方案2】:

对于有类似问题的其他人:确保 userSessionFactory.getCurrentSession() 返回您期望的结果。

在我的例子中,用户会话附加到当前线程(使用ThreadLocal)。现在,一个辅助框架在一个新的后台线程中执行了我的一些代码 -> ThreadLocal 返回了 null,尽管我知道用户已登录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 2023-04-01
    • 2011-07-17
    • 1970-01-01
    相关资源
    最近更新 更多