上下文&依赖注入:如何注入接口的实现?

时间:2017-04-07 01:16:30

标签: dependency-injection cdi javax-inject

我正处于CDI的初级阶段,并尝试使用字段注入注入接口的实现,如下所示:

AutoService.java

package com.interfaces;

public interface AutoService {
    void getService();
}

BMWAutoService.java

package com.implementations;

import javax.inject.Named;

import com.interfaces.AutoService;

@Named("bmwAutoService")
public class BMWAutoService implements AutoService {

    public BMWAutoService() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public void getService() {
        System.out.println("You chose BMW auto service");

    }

}

AutoServiceCaller.java

package com.interfaces;

public interface AutoServiceCaller {
    void callAutoService();
}

AutoServiceCallerImp.java

package com.implementations;

import javax.inject.Inject;
import javax.inject.Named;

import com.interfaces.AutoService;
import com.interfaces.AutoServiceCaller;

public class AutoServiceCallerImp implements AutoServiceCaller {

    @Inject
    @Named("bmwAutoService")
    private AutoService bmwAutoService;

    public AutoServiceCallerImp() {

    }

    @Override
    public void callAutoService() {
        bmwAutoService.getService();

    }

}  

TestDisplayMessage.java

package com.tests;

import com.implementations.AutoServiceCallerImp;
import com.interfaces.AutoServiceCaller;

public class TestDisplayMessage {

    public TestDisplayMessage() {
        // TODO Auto-generated constructor stub
    }

    public static void main(String[] args) {

        AutoServiceCaller caller = new AutoServiceCallerImp();

        caller.callAutoService();

    }

}  

当我运行TestDisplayMessage.java时,预期结果将是“您选择了宝马汽车服务”,但我得到如下NullPointerException:

Exception in thread "main" java.lang.NullPointerException
    at com.implementations.AutoServiceCallerImp.callAutoService(AutoServiceCallerImp.java:21)
    at com.tests.TestDisplayMessage.main(TestDisplayMessage.java:16)

无法弄清楚我在这里错过了什么。请帮忙。谢谢。

1 个答案:

答案 0 :(得分:0)

好吧,你似乎误解了CDI的概念 - 这个想法是你将bean生命周期留给了CDI容器。这意味着CDI将为您创建创建配置bean。换句话说,您应该通过调用new来创建bean。如果你这样做,CDI不会知道它,也不会注入任何东西。

如果您处于SE环境中,我认为您使用main方法进行测试,那么您希望使用Weld(CDI实现)SE工件(我猜你这样做)。 在那里,您需要启动CDI容器。请注意,如果您在服务器上开发经典EE应用程序,则不要这样做,因为服务器将为您处理它。现在,启动Weld SE容器的最基本方法是:

Weld weld = new Weld();
try (WeldContainer container = weld.initialize()) {
  // inside this try-with-resources block you have CDI container booted
  //now, ask it to give you an instance of AutoServiceCallerImpl
  AutoServiceCallerImpl as = container.select(AutoService.class).get();
  as.callAutoService();
}

现在,你的代码第二个问题。 @Named的用法适用于EL解析。例如。在JFS页面中,您可以直接访问bean。 您可能想要的是区分多个AutoService实现并选择给定的实现。因为CDI有限定符。查看this documentation section以获取有关如何使用它们的更多信息。