【问题标题】:Scope of Singletons单例的范围
【发布时间】:2014-11-02 10:52:21
【问题描述】:

我正在使用单例 bean 向我的 Java EE 应用程序提供存储在数据库中的配置值。

@Singleton
public class ConfigurationProvider {

  private final Map<String, ConfigurationEntity> configMap = new HashMap<>();

  @PersistenceContext(unitName = DatabaseConstants.PERSISTENCE_UNIT)
  private EntityManager em;

  public String getConfiguration(String key) {
    if (configMap.containsKey(key)) {
        return configMap.get(key).getValue();
    }

    ConfigurationEntity config = em.find(ConfigurationEntity.class, key);
    em.detach(config);
    if (config == null) {
        throw new RuntimeException("Configuration not found for " + key);
    }
    configMap.put(key, config);
    return config.getValue();
  }

  public void clear() {
    configMap.clear();
  }

  public Collection<ConfigurationEntity> getCurrentConfigurationState() {
    return configMap.values();
  }
 }

生产者让我注入值

public class ConfigurationProducer {

  @Inject
  private ConfigurationProvider configProvider;

  @Produces
  @ConfigurationValue
  public String getConfiguration(InjectionPoint ip) {
    String key = createKey(ip);
    return configProvider.getConfiguration(key);
  }

这里是一个例子

@Inject
@ConfigurationValue
private Instance<String> endpoint;

这会从数据库中加载端点。出于测试原因,该值应该是可变的。 所以你看到的是一个 ejb 模块的一部分。

为了重新加载这些值,我创建了一个提供该功能的 REST 接口。此 REST 服务是与 ejb 模块一起打包在一个 ear 文件中的附加 WAR 的一部分。

@Path("/configuration")
public class ConfigurationResource {

  @EJB
  private ConfigurationProvider configurationProvider;

  @GET
  @Path("/current")
  @Produces({ "application/json" })
  public Collection<ConfigurationEntity> getCurrentConfiguration() {
    return configurationProvider.getCurrentConfigurationState();
  }
}

但问题是,战争有它自己的配置提供者实例。所以我无法重新加载“缓存”。 为什么我的单例中有两个实例在同一个耳朵里?

【问题讨论】:

    标签: java rest singleton jboss7.x java-ee-6


    【解决方案1】:

    我认为您不能那样使用 ConfigurationProvider EJB。该 EJB 需要有一个远程接口,并且您可以从外部 WAR 访问它作为任何远程 EJB。外部 WAR 有一个不同的类加载器,因此它不会找到 EAR 单例 EJB。

    【讨论】:

    • 嗨 bitkot,两个模块都在同一个 ear 文件中。
    【解决方案2】:

    您似乎同时使用 CDI 的 @Inject 和 EJB 的 @EJB 来注入您的 ConfigurationProvider 实例。考虑到您没有同步对 map 的访问并且您使用的是非线程安全的 EntityManager,您可能应该使用@EJB。

    也就是说,您只需对代码稍作改动:

    public class ConfigurationProducer {
        @EJB
        private ConfigurationProvider configProvider;
    
        @Produces
        @ConfigurationValue
        public String getConfiguration(InjectionPoint ip) {
            String key = createKey(ip);
            return configProvider.getConfiguration(key);
    }
    

    【讨论】:

      【解决方案3】:

      解决方案:

      Maven 第二次将 ejb 模块打包到 war 的 lib 文件夹中。我必须将 pom.xml 中的范围设置为提供。使用 ejb 模块,它可以毫无例外地工作,但对于战争,您必须手动完成。

      现在可以了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多