我是JavaEE的新手,也是依赖注入的概念。但是我对它有一个公平的理解,即使我不知道它可以使用的所有方式。
我有一个本地界面如下:
@Local
public interface MyInterfaceLocal {
SomeType getMeSometype();
}
实现此接口的类是无状态EJB。
@Stateless
public class MyInterfaceImpl {
public SomeType getMeSomeType() {
//Some implementation details...
ExternalLibraryClass externalLib = new ExternalLibrary(arg1, arg2);
return externalLib.externalLibMethod();
}
}
现在的问题是,我怎样才能避免实例化externalLib
并让它以某种方式注入?例如,如果这是我使用接口创建的另一个EJB,那么我可以简单地让EJB容器处理实例化,并使用如下所示的@EJB
注释。
@Stateless
public class MyInterfaceImpl {
@EJB
AnotherInterface anotherInterfaceImpl;
public SomeOtherType getMeSomeType() {
//Some implementation details...
return anotherInterfaceImpl.someMethod();
}
}
我希望能够为我正在使用的外部库做这样的事情,因为它允许我:
MyInterfaceImpl
类进行单元测试时,轻松注入模拟。到目前为止我一直在看 -
创建一个参数为ExternalLibrary
的包装器方法,因此可以执行某种手动方法参数注入。这仍然使我的实现与底层库紧密耦合。 (或者我做得不对)
使用Context & Dependency Injection
容器进行注入(就像EJB容器的工作方式一样。我知道它不一样)。研究了使用Producers
的能力。虽然我理解Producers
对CDI的所作所为,但我无法理解如何利用它?或者即使我走在正确的道路上?
更新 我找到了一些文章,帮助我更好地理解了CDI制作人员,并尝试采用这种方法但面临另一个问题。所以现在我有:
ExternalLibraryProducer.java
public class ExternalLibraryProducer {
@Produces
private ExternalLibraryClass1 extrnalLibraryClassProducer() {
return new ExternalLibraryClass1("SomeString", 7);
//The constructor actually takes a string and another commplex type
//as parameters. I am keeping it a little simple here.
//I am trying to set the ExternalLibraryClass1() arguments
//programmatically at runtime.
}
}
现在我想要生成的对象的构造函数接受参数,让我们说一个字符串和整数。我以为我可以创建一个Qualifier
来传递这些参数来生成我想要的对象。
ExternalLibraryClass1Qualifier.java
@Qualifier
@Retention(RUNTIME)
@Target({METHOD})
public @interface ExternalLibraryClass1Qualifier {
String argument1();
Int argyment2(); //This is actually another complex type. Keeping it
//simple here.
}
现在我想做的是,我希望在运行时以编程方式设置参数值(假设,从属性文件中)。我无法弄清楚如何做到这一点。所以我的最终注射将如下所示。
@Stateless
public class MyInterfaceImpl {
@Inject
@ExternalLibraryClass1Qualifier(argument1 = "something", argument2 = 7)
ExternalLibrary externalLib;
public SomeType getMeSomeType() {
//Some implementation details...
return externalLib.externalLibMethod();
}
}
感谢任何指导。
答案 0 :(得分:0)
您可以让ExternalLibrary
的生成器方法接受创建对象所需的参数,并且可以通过CDI生成器生成这些参数。
public class ExternalLibraryProducer {
private String name;
private int age;
public ExternalLibraryProducer() {
// set name and age from properties file or elsewhere
// or you can set them individually on their respective producer methods, but might be costly considering you need to read the properties file twice
}
@Produces
public String name() {
return name;
}
@Produces
public int age() {
return age;
}
....
@Produces
private ExternalLibraryClass1 extrnalLibraryClassProducer(String name, int age) {
// Or you can use them directly here, if you opt to not separate this config from the dependencies
return new ExternalLibraryClass1(argument, age);
}
}
答案 1 :(得分:0)
CDI制作人是一种去往这里的方式,唯一的问题是,你究竟想要如何构建它们。
既然你说参数来自属性文件,我建议你反转方法,让生产者方法检查属性文件并提取值(或者询问任何"读者"哪个做到了之前和缓存它):
@Produces
private ExternalLibraryClass1 produceExternalLibraryInstance() {
// read the properties from the file or from any cache you use
String arg1 = PropertyReader.getarg1();
Integer arg2 = PropertyReader.getArg2();
// create object with those args
return new ExternalLibraryClass1(arg1, arg2);
}
有了这个,你显然不需要限定词,然后只需@Inject ExternalLibraryClass1
。
请注意,生成器将根据您何时创建注入ExternalLibraryClass1
的对象进行调用 - 确保您可以很快从属性文件中获取args。 (如果你有一些缓存,那么当产品读数时应该会有麻烦吗)