如何在JavaEE应用程序中注入没有接口,外部库类?

时间:2017-09-11 02:56:10

标签: java-ee dependency-injection mocking cdi

我是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();
    }
}

我希望能够为我正在使用的外部库做这样的事情,因为它允许我:

  1. 将当前正在使用的基础外部库以最小的更改更改为我的代码库。如果需要,可以改为更好的。
  2. 当我想对MyInterfaceImpl类进行单元测试时,轻松注入模拟。
  3. 到目前为止我一直在看 -

    1. 创建一个参数为ExternalLibrary的包装器方法,因此可以执行某种手动方法参数注入。这仍然使我的实现与底层库紧密耦合。 (或者我做得不对)

    2. 使用Context & Dependency Injection容器进行注入(就像EJB容器的工作方式一样。我知道它不一样)。研究了使用Producers的能力。虽然我理解Producers对CDI的所作所为,但我无法理解如何利用它?或者即使我走在正确的道路上?

    3. 更新 我找到了一些文章,帮助我更好地理解了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();
          }
      }
      

      感谢任何指导。

2 个答案:

答案 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。 (如果你有一些缓存,那么当产品读数时应该会有麻烦吗)