如何以编程方式查找和注入CDI托管bean,其中限定符包含类的名称

时间:2015-04-08 23:51:24

标签: java java-ee dependency-injection cdi jboss-weld

我正在尝试以编程方式查找并注入CDI托管bean,其中限定符包含类的名称(不是我要注入的类),但是我遇到的问题是我正在使用的代码查找正确的bean总是返回null

我想要注入的bean使用一个名为@CQRSCommandHandler的自定义注释进行注释,该注释包含用作限定符的类的名称,bean也实现了一个名为CommandHandler的接口。我使用限定符的类实现了接口Command

基于我对CDI的一些有限知识,我认为为了以编程方式查找已使用@CQRSCommandHandler注释限定的正确bean,我需要扩展AnnotationLiteral然后我可以使用Instance选择bean。

@CQRSCommandHandler注释的代码如下:

@Qualifier
@Documented
@Retention(value= RetentionPolicy.RUNTIME)
public @interface CQRSCommandHandler {
    Class<? extends Command> command();
}

扩展AnnotationLiteral的代码如下:

public class CQRSCommandHandlerQualifier extends AnnotationLiteral<CQRSCommandHandler> implements CQRSCommandHandler {

    private static final long serialVersionUID = 1L;
    private final Class<? extends Command> command;

    public CQRSCommandHandlerQualifier(Class<? extends Command> command) {
        this.command = command;
    }

    @Override
    public Class<? extends Command> command() {
        return command;
    }

}

我用于使用CDI查找正确bean的代码如下:

@Inject
@Any
private Instance<CommandHandler> commandHandlerInstance;

private CommandHandler findCommandHandlerFor(Command command) {

    CommandHandler commandHandler = commandHandlerInstance.select(new CQRSCommandHandlerQualifier(command.getClass())).get();  //This always returns null
    return commandHandler;
}

尽管谷歌搜索了好几个小时,但我无法理解为什么commandHandlerInstance.select(new CQRSCommandHandlerQualifier(command.getClass())).get();不会返回已使用@CQRSCommandHandler (command = MyCommand.class)注释的bean实例,其中bean实现了CommandHandler接口并且MyCommand.class实现了接口Command

这是以编程方式查找和注入CDI托管bean的正确方法,其中限定符包含类的名称吗?如果是这样,上面的代码我哪里出错了?如果没有,达到相同最终结果的最佳方法是什么?


更新

以下代码是我正在尝试查找的bean的示例实现:

@CQRSCommandHandler(command = CreateToDoItemCommand.class)
public class CreateToDoItemCommandHandler implements CommandHandler {

    @Override
    public <R> Object handle(Command command) {
        System.out.println("This is the CreateToDoItemCommandHandler");
        return null;
    }
}

以下代码是CommandHandler的接口:

public interface CommandHandler {

    public <R> Object handle(Command command);

}

以下代码是我在限定符中用作参数的类的示例:

public class CreateToDoItemCommand implements Command {

    private String todoId;
    private String description;

    public CreateToDoItemCommand(String todoId, String description) {
        this.todoId = todoId;
        this.description = description;
    }

    public String getTodoId() {
        return todoId;
    }

    public String getDescription() {
        return description;
    }

}

我已经逐步完成了Eclipse中的代码,似乎Instance的{​​{1}}对象是commandHandlerInstance


更新2

正如@redge所建议的那样,我将实例化的每一步分成如下一行:

null

问题似乎出现在这行代码private CommandHandler findCommandHandlerFor(Command command) { CQRSCommandHandlerQualifier qualifier = new CQRSCommandHandlerQualifier(command.getClass()); Instance<CommandHandler> instance = commandHandlerInstance.select(qualifier); CommandHandler commandHandler = instance.get(); return commandHandler; } 上,因为Instance<CommandHandler> instance = commandHandlerInstance.select(qualifier);对象NullPointerExceptionInstance

,因此可能会引发commandHandlerInstance

我在GlashFish 4上运行此代码,它附带了Weld 2.0.0 SP1,但我也尝试在GlashFish 4.1上运行相同的代码并安装了Weld版本2.2.10.SP1这是最新的Maven Central但同样的问题也出现了。

1 个答案:

答案 0 :(得分:0)

你有GlassFish 4.1。我怀疑你有一个beans.xml文件,如果你这样做,应该根据你当前的设置标记为bean-discovery-mode="all"。如果不这样做,或者您使用bean-discovery-mode="annotated",那么您需要为每个命令添加一个定义注释的bean,例如:每个命令都@ApplicationScoped,以便可以解决它们。