我有两bean,它实现了接口
@Storage(StorageType.LOCAL)
public class LocalStorage implements StorageService {
// [...]
}和
@Storage(StorageType.REMOTE)
public class RemoteStorage implements StorageService {
// [...]
}在服务类中,我使用的是注入的StorageService。
@Stateless
public class DocumentService {
@Inject
@Storage(StorageType.REMOTE)
private StorageService storageService;
// [...]}
这很好,但是我希望能够在不改变源代码的情况下从外部配置StorageType。
所以我创造了一个制作人:
@Singleton
public class StorageServiceProducer {
@Inject
@ConfigurationValue("storage.type") // Injects values from a properties file
private String storageType;
@Produces
public StorageService produceStorageService(InjectionPoint injectionPoint) {
if (storageType.equals("remote")) {
return new RemoteStorage();
} else {
return new LocalStorage();
}
}
}...and从我的bean中删除了@Storage注释:
public class LocalStorage implements StorageService {
// [...]
}和
public class RemoteStorage implements StorageService {
// [...]
}但是现在我得到了一个模糊依赖异常,大概是因为生产者本身的存在。为了强制生产者使用,我发现我可以使用"@Vetoed“注释。
这似乎是可行的,,但是由于bean不再被管理,所以我的实现中的任何注入值都缺少。
public class RemoteStorage implements StorageService {
@Inject
@ConfigurationValue("project.id")
private String projectId;
// [...]
}以下是我的问题:
编辑:我使用的是CDI 1.2和bean发现模式=“all”。
发布于 2018-01-10 15:13:38
这是一种对动态生产者的正确方法,但请注意,CDI通常是相当静态的,所以动态地尝试可能并不总是感觉顺利。现在,您遇到的是自己创建实例(使用new),因此CDI只知道结果对象,无法控制它。它不会注入到字段/构造函数/.你的豆子。
从我的头顶上我可以想到两种选择:
这意味着您不会自己创建bean,而您的生产者只会交出正确的bean。这种方法的好处是CDI处理了所有的问题,因此您的注入将不需要任何额外的工作。此外,拦截、装饰、事件处理程序等都将如您所期望的那样工作。不好的一面是,如果你有更多的实现,或者随着时间的推移要增加更多的实现,那么事情就会变得一团糟。
要实现这一点,您可以(例如)限制您的实现的类型集,以便它们在您的@Inject StorageService时不适合。
@Typed({Object.class, RemoteStorage.class})
public class RemoteStorage implements StorageService { ....}并对其他存储实现执行同样的操作。然后,从你的制片人那里,你可以这样做:
@ApplicationScoped
public class StorageServiceProducer {
@Inject
@ConfigurationValue("storage.type") // Injects values from a properties file
private String storageType;
// there should be no ambiguity injecting specific impl type
@Inject
RemoteStorage remoteStorage;
@Inject
LocalStorage localStorage;
@Produces
public StorageService produceStorageService(InjectionPoint injectionPoint) {
if (storageType.equals("remote")) {
return remoteStorage;
} else {
return localStorage;
}
}}
在这种方法中,我们保持代码的原样,只添加一个将注入结果实例的代码段。好处是,它可能更容易扩展,而且相当简单。缺点是你没有得到一个完整的CDI bean,你只是把一个实例交给CDI:“嘿,如果有人要一个'StorageService‘类型的bean,你就给他这个,哦,请注入它。”拦截,装饰,观察者和其他的东西不会在那里起作用。更准确地说,您只需将这个实例交给CDI所称的InjectionTarget。
以下是如何:
@ApplicationScoped
public class StorageServiceProducer {
@Inject
@ConfigurationValue("storage.type") // Injects values from a properties file
private String storageType;
@Inject
BeanManager bm;
@Produces
public StorageService produceStorageService(InjectionPoint injectionPoint) {
StorageService result = null;
if (storageType.equals("remote")) {
result = RemoteStorage();
} else {
result = LocalStorage();
}
// make it an injection target, it's gonna be something like this
CreationalContext<Object> ctx = bm.createCreationalContext(null);
InjectionTarget<Object> injectionTarget = (InjectionTarget<Object>) beanManager
.getInjectionTargetFactory(bm.createAnnotatedType(result.getClass())).createInjectionTarget(null);
injectionTarget.inject(result, ctx);
// return result which was injected into
return result;
}}
发布于 2018-01-10 15:10:58
一个简单的解决方案是使用@New限定符。
首先,您需要从自动发现中排除这两个bean实现。不确定您正在运行哪个版本的CDI --从1.1开始,您可以使用@Vetoed注释。或者使用beans.xml来回答这个问题:如何用CDI1.0排除类的扫描 (虽然它是特定的)
@Vetoed
public class LocalStorage implements StorageService {
// [...]
}
@Vetoed
public class RemoteStorage implements StorageService {
// [...]
}然后使用@New限定符将这两个实现注入producer方法:
@Singleton
public class StorageServiceProducer {
@Inject
@ConfigurationValue("storage.type") // Injects values from a properties file
private String storageType;
@Produces
public StorageService produceStorageService(@New LocalStorage localStorage, @New RemoteStorage remoteStorage) {
if (storageType.equals("remote")) {
return remoteStorage;
} else {
return localStorage;
}
}
}发布于 2018-05-04 20:39:29
我认为您可以像现在一样使用您的两个Storage实现,但是删除这些限定符并非常显式地键入它们以排除StorageService (这还假设它们已经通过某种机制以启用been的形式添加到CDI系统中,例如,如果它们也被用bean定义注释或通过扩展以编程方式添加注释的话):
@Typed(LocalStorage.class)
public class LocalStorage implements StorageService {
// [...]
}
@Typed(RemoteStorage.class)
public class RemoteStorage implements StorageService {
// [...]
}接下来,将它们注入到生产者方法的依赖项中:
@Produces
public StorageService produceStorageService(LocalStorage localStorage, RemoteStorage remoteStorage) {
if (storageType.equals("remote")) {
return remoteStorage;
} else {
return localStorage;
}
}https://stackoverflow.com/questions/48189066
复制相似问题