我正在尝试以编程方式查找并注入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);
对象NullPointerException
是Instance
commandHandlerInstance
我在GlashFish 4上运行此代码,它附带了Weld 2.0.0 SP1,但我也尝试在GlashFish 4.1上运行相同的代码并安装了Weld版本2.2.10.SP1这是最新的Maven Central但同样的问题也出现了。
答案 0 :(得分:0)
你有GlassFish 4.1。我怀疑你有一个beans.xml文件,如果你这样做,应该根据你当前的设置标记为bean-discovery-mode="all"
。如果不这样做,或者您使用bean-discovery-mode="annotated"
,那么您需要为每个命令添加一个定义注释的bean,例如:每个命令都@ApplicationScoped
,以便可以解决它们。