【问题标题】:Inner dependency is not being injected (Weld + JavaSE)内部依赖没有被注入(Weld + JavaSE)
【发布时间】:2015-10-13 12:34:16
【问题描述】:

我正在通过添加 CDI 重构旧模块。

我以

结尾
public interface ApiFactory {
  ...
}

public class ApiFactorySp
    implements ApiFactory {
  @Inject
  UrlProducer urlProducer;  // <-- Does not get injected
  ...
}

public interface UrlProducer {
    public String getUrl();
}

@Alternative
public class UrlProducerTest
    implements UrlProducer {

    @Override
    public String getUrl() {
        return "https://myTestEnv.mydomain/myWebApp";
    }
 }

为了测试,我在META-INF中创建了一个beans.xml文件:

<beans
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
  bean-discovery-mode="all">
    <alternatives>
      <class>myOrg.myProject.myPackage.UrlProducerTest</class>
    </alternatives>
</beans>

为了测试它,我正在做in this blog所示的操作

public class WeldContext {

    public static final WeldContext INSTANCE = new WeldContext();

    private final Weld weld;
    private final WeldContainer container;

    private WeldContext() {
        this.weld = new Weld();
        this.container = weld.initialize();
        Runtime.getRuntime().addShutdownHook(new Thread() {

            @Override
            public void run() {
                weld.shutdown();
            }
        });
    }

    public <T> T getBean(Class<T> type) {
        return container.instance().select(type).get();
    }
}

public class WeldJUnit4Runner extends BlockJUnit4ClassRunner {

    public WeldJUnit4Runner(Class<Object> clazz) throws InitializationError {
        super(clazz);
    }

    @Override
    protected Object createTest() {
        final Class<?> test = getTestClass().getJavaClass();
        return WeldContext.INSTANCE.getBean(test);
    }
}

现在,当我尝试测试逻辑时,我会这样做

@RunWith(WeldJUnit4Runner.class)
public class MyTest {
     @Inject
     UrlProducer urlProducer;         

     @Inject
     ApiFactory apiFactory;

     @Test
     public void test() {
         apiFactory.doSomethingThatRequiresUrlProducer();
     }
 }

当我运行它时,两个测试属性都被注入,但我得到了 NPE,因为 apiFactory 实例内的 urlProducer 属性尚未分配值。

为什么 Weld 无法识别 ApiFactory 中的 @Inject 属性?

JDK 7、Weld 2.2.10、Junit 4.12

更新:发布问题后,开始尝试一个更简单的全新项目(只有两个接口和三个类)。使用 Weld “独立”并没有解决问题,使用 CDI-Unit 确实解决了它。

然后我修改了我的原始项目以使用 CDI-Unit,但它没有任何改进。之后,我将ApiFactory 中的UrlProducerTest 注入从字段更改为构造函数(即定义@Inject ApiFactory(UrlProducer urlProducer) 构造函数)解决了它。我仍然没有尝试使用“独立”焊接(即明天)的这种解决方案,但我仍然想知道为什么现场注入不起作用。

【问题讨论】:

  • 你确定NPE不是因为没有注入apiFactory吗?
  • @A.Panzer 是的,我确定apiFactory 被注入了。但是当我要回复时,我认为我很确定,因为使用 UrlProducer 的代码是 在构造函数中 :-*> 并且它会导致在实例化过程中引发异常......我明天必须检查它,但也许你想重写你的答案以考虑到这一点。

标签: java cdi weld


【解决方案1】:

如果UrlProducerTest 是一个替代方案并且你想注入这个bean,那么这个类应该被添加到beans.xml&lt;alternatives&gt; 标记中。

编辑

我相信如果某些 bean 不能被注入,你会得到“不满意/不明确的依赖”消息的异常。如果您使用返回 null 的 CDI producer 方法,则可以注入 Null,但这不是您的情况。

所以如果控制台没有错误,我有两个假设:

  1. 注入根本不起作用,您会得到 NPE,因为 apiFactory 为空

  2. 您在注入前使用urlProducer。例如,来自构造函数或初始化块(未提供apiFactory.doSomethingThatRequiresUrlProducer())。所以把这个逻辑移到某个方法上,并通过@PostConstruct 注释它

【讨论】:

  • 很好发现,不幸的是 UrlProducerTest 被声明为替代方案(我在代码中修改了类的名称以获得更简单的版本,但在 beans.xml 文件中未修改;UrlSharepointTest上一版中出现的有效UrlProducerTest
  • 确实,我错过了在构造函数中使用该属性的要点(正如我所说,我正在重构一些非 CDI 代码)。显然,由于字段注入发生在 bean 创建之后(即,在 new 命令完成之后),我无法使用构造函数内的字段值。将逻辑移至 @PostConstruct 方法。
【解决方案2】:

因为ApiFactorySp 不是 CDI bean。您需要使用 @Named 注释该类,以将该类标识为 CDI bean,以便 CDI 执行依赖注入。

【讨论】:

  • 谢谢你,但你错了。 CDI bean 不需要注释; @Named 可用于使 bean 可通过 EL 访问,但不需要直接注入:docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html。此外,从我的问题文本中,很明显 Weld 正在发现这些 bean,因为它们是在我的测试实例中注入的。
猜你喜欢
  • 2021-12-08
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多