【问题标题】:CDI Produces vs. Service Locator PatternCDI 生产与服务定位器模式
【发布时间】:2014-11-25 20:20:27
【问题描述】:

请阅读下面我的场景并告诉我哪种方法更适合我:

  1. CDI with producer method
  2. service locator pattern

场景:

  • 有一个接口,例如ConfigurationManager。
  • 它有三种完全不同的实现方式。它们中的每一个都位于独立的 EAR 中,并带有必要的库。我们有 MemoryConfigurationManager、FileConfigurationManager 和 JpaConfigurationManager。
  • 有一个应用程序 (EAR)。它需要使用一个配置管理器。

也许稍后,开发人员将创建接口的第 4 个实现并将其安装到应用程序服务器中并重新配置主应用程序,以便应用程序使用接口的最新实现。主应用程序始终只使用一种接口实现,管理员可以重新配置使用哪种实现。

这里我不能使用简单的 CDI,因为实现在不同的 EAR 中,并且应用程序也在一个单独的耳朵中,所以它们有不同的类加载器。简单的@Inject 在 EAR 之间不起作用。

所以我有两种方法:

  • 如果我想使用 CDI 而不是我需要使用 @Produces 方法。它提供了一种注入非 bean 对象的方法。
  • 我可以使用服务定位器模式。这种查找速度很快,因为它有自己的缓存。

当然,在 CDI @Produces 方法后面,我也可以使用服务定位器模式。不同实现的服务 URL 来自外部配置文件。如果有人创建了 ConfigurationManager 的新实现并将其安装到 Java EE 容器中,那么他需要将新的服务 url 放入配置文件中。

那么哪种方法更好呢? (1)还是(2)?或者还有另一种明确的方法来实现这个功能? :-)

我更喜欢 (2)。
我认为 CDI + Producers 带来了更多不必要的课程。

【问题讨论】:

    标签: cdi service-locator


    【解决方案1】:

    我不会考虑如何获取 Service-Proxy,在这种情况下,您的两个场景都可以正常工作(正如您已经发现的那样,您甚至可以使用 @Produces 注释您的 ServiceLocator)。

    想想使用 Service 的类将如何获取代理实例。您想读取属性并在每个构造函数中定位服务吗?你会有一个工厂,每个实现都有一个方法吗? SPI-服务加载?您将如何使用该服务测试课程?

    在所有这些情况下,依赖注入都有很大的优势,因为它分离了关注点并在客户端和实现之间定义了清晰的依赖关系。我的最佳实践:只要有选择,就选择 (C)DI。如果您将 ServiceLocator/PropertyReader 方法与 @Produces 注释相结合,您甚至不需要编写更多类,但您会获得很多回报。

    【讨论】:

    • 所以你建议使用cdi。我在考虑你的评论,我同意你的看法。我将用 cdi 来实现它,我会回来找你的。谢谢。
    【解决方案2】:

    所以我为 CDI 创建了一些类。它看起来不错,而且效果很好。

    具有类型的限定符类:

    @Qualifier
    @Retention(RUNTIME)
    @Target( {TYPE, METHOD, FIELD, PARAMETER} )
    public @interface DaoQualifier
    {
        public enum DatasourceType { FILE, JPA, MEMORY }
    
        public DatasourceType type();
    }
    

    工厂类,它返回正确的接口实例:

    @ApplicationScoped
    public class ConfigurationReaderDaoFactory implements Serializable
    {
        private static final long serialVersionUID = -7097322271912690164L;
        private static final Logger LOGGER = Logger.getLogger( ConfigurationReaderDaoFactory.class.getName() );
        private final String LOG_MESSAGE = "getting ConfigurationReaderDao ejb remote reference for %s datasource";
    
        @Produces
        @DaoQualifier(type = DatasourceType.MEMORY)
        public ConfigurationReaderDao getMemoryDao() throws NamingException
        {
            LOGGER.finer( String.format(LOG_MESSAGE,  DatasourceType.MEMORY) );
    
            String jndi = ""java:global/earName/ejbName/MemoryConfigurationReaderDao!a.b.c.ConfigurationReaderDao";";
            return (ConfigurationReaderDao) InitialContextGenerator.getInitialContext().lookup(jndi);
        }
    
        @Produces
        @DaoQualifier(type = DatasourceType.JPA)
        public ConfigurationReaderDao getJpaDao() throws NamingException
        {
            LOGGER.finer( String.format(LOG_MESSAGE,  DatasourceType.JPA) );
    
            String jndi = ""java:global/earName/ejbName/JpaConfigurationReaderDao!a.b.c.ConfigurationReaderDao";";
            return (ConfigurationReaderDao) InitialContextGenerator.getInitialContext().lookup(jndi);
        }
        ...
    }
    

    通过@Inject 注解易于使用:

    public class ConfigurationReaderService
    {
        @Inject
        @DaoQualifier(type = DatasourceType.MEMORY)
        private ConfigurationReaderDao configurationReaderDaoService;
    
        public String getStringSystemParam(final String key)
        {
            String value = null;
    
            if (key != null)
            {
                value = configurationReaderDaoService.getStringSystemParam(key);
            }
        }
    }
    

    我喜欢这个解决方案,因为它很容易阅读和理解。

    我只剩下三个问题了:

    (1) 我需要弄清楚的最后一件小事是:在我当前的实现中,类型参数是硬编码的:

    @Inject
    @DaoQualifier(type = DatasourceType.MEMORY)
    private ConfigurationReaderDao configurationReaderDaoService;
    

    type 参数来自管理员管理的应用程序配置。所以我需要以某种方式动态注入接口的正确实现,它依赖于字符串变量的简单值。

    我想我需要以某种方式使用@Any 注释。

    (2) 我尝试在ConfigurationReaderDaoFactory 类的开头使用@RequestScoped 注释,但它不起作用。我得到了一个 WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped 异常。

    (3) 为什么在我的情况下使用 CDI 注入比直接使用我的 ConfigurationReaderDaoFactory 类更好?如果我直接使用我的工厂类,我不需要DaoQualifier 类,也不需要弄清楚动态注入过程。更少的类和代码总是更好:-)

    【讨论】:

      猜你喜欢
      • 2016-02-06
      • 1970-01-01
      • 1970-01-01
      • 2015-08-12
      • 2011-11-17
      • 2019-10-04
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      相关资源
      最近更新 更多