请仔细阅读我的情景并告诉我哪种方法更适合我的情况:
情景:
也许以后,开发人员将创建接口的第4个实现并将其安装到应用服务器中并重新配置主App,以便应用程序使用最新的接口实现。主App总是只使用一个接口实现,管理员可以重新配置使用哪个实现。
这里我不能使用简单的CDI,因为实现在不同的EAR中,并且应用程序也处于分离的耳朵中,因此它们具有不同的类加载器。简单的@Inject
在EAR之间无效。
所以我有两种方式:
@Produces
方法。它提供了一种注入不是bean的对象的方法。当然,在CDI @Produces
方法的后面,我也可以使用服务定位器模式。不同实现的服务URL来自外部配置文件。如果某人创建了ConfigurationManager的新实现并将其安装到Java EE容器中,那么他需要将新服务URL放入配置文件中。
那么哪种方法更好? (1)或(2)?或者还有另一种明确的方法来实现此功能? : - )
我更喜欢(2)。
我认为CDI +制作人会带来更多不必要的课程。
答案 0 :(得分:1)
我会更少考虑如何获取服务代理,在这种情况下,您的两个方案都将工作相同(您已经发现,甚至可以使用@Produces注释您的ServiceLocator)。
考虑使用Service的类将如何获取代理实例。您想阅读属性并在每个构造函数中找到服务吗?你有一个工厂每个实施一种方法吗? SPI服务加载?您打算如何使用该服务测试课程?
在所有这些情况下,依赖注入都有很大的优势,因为它分离了关注点并定义了客户端和实现之间的明确依赖关系。我的最佳实践:每当你有选择时,去(C)DI。如果将ServiceLocator / PropertyReader方法与@Produces注释结合使用,您甚至可以编写更多类,但是您可以获得更多回报。
答案 1 :(得分:0)
所以我为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)我需要弄清楚的最后一件小事是:在我当前的实现中,type参数是硬编码的:
@Inject
@DaoQualifier(type = DatasourceType.MEMORY)
private ConfigurationReaderDao configurationReaderDaoService;
type参数来自应用程序配置,由管理员管理。所以不知怎的,我需要动态地注入接口的正确实现,而它依赖于一个简单的String变量值。
我想我需要以某种方式使用@Any
注释。
(2)我试图在@RequestScoped
类的开头使用ConfigurationReaderDaoFactory
注释,但它没有用。我得到了一个WELD-001303:没有用于范围类型javax.enterprise.context.RequestScoped异常的活动上下文。
(3)为什么使用CDI注入比在我的情况下直接使用ConfigurationReaderDaoFactory
类更好?如果我直接使用我的工厂类,我不需要DaoQualifier
类,我不需要弄清楚动态注入过程。较少的类和代码总是更好: - )