有什么方法可以将依赖项注入到手动创建的对象中吗?
public class MyCommand {
@Inject Repository repository;
}
public Repository {
@Inject EntityManager em;
}
MyCommand command = new MyCommand();
信息库已在Jersey ResourceConfig中正确注册,并且可以注入通过CDI容器创建的对象中,例如资源类。
但是,由于我自己创建了Command,因此@Inject注释将被忽略。
有没有办法在@Inject和@Context旁边获取注册的类?
像Application.get(Repository.class)之类的东西
public class MyCommand {
Repository repository;
public MyCommand() {
repository = Application.get(Repository.class);
}
}
-----编辑-----
感谢您的帮助和重新思考,我找到了解决问题的方法。
第一件事是可以将ServiceLocator注入而无需对对象进行任何预准备。
第二件事是我从带有执行方法的普通命令转移到命令总线系统。
这样做的原因是我无法控制命令的创建,因此这里有干净的方法来注入依赖项。
新方法如下所示:
class CommandBus {
private final ServiceLocator serviceLocator;
@Inject
public CommandBus(ServiceLocator serviceLocator) {
this.serviceLocator = serviceLocator;
}
public void dispatch(Command command) {
Class handlerClass = findHandlerClassForCommand(command);
CommandHandler handler = (CommandHandler) serviceLocator.getService(handlerClass);
handler.handle(command);
}
}
interface CommandHandler {
void handle(Command command);
}
interface Command {
}
class ConcreteCommand implements Command {
// I'm just a dto with getters and setters
}
class ConcreteHandler implements CommandHandler {
private final SomeDependency dependency;
@Inject
public ConcreteHandler(SomeDependency dependency) {
this.dependency = dependency;
}
@Override
public void handle(ConcreteCommand command) {
// do some things
}
}
在我的资源中,我有这样的东西:
@Path("/some-resource")
class Resource {
@Context
private CommandBus bus;
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void runCommand(ConcreteCommand command) {
bus.dispatch(command);
}
}
最佳答案
正如jwells指出的-HK2是一个注入框架:)
我花了一些时间研究它-我不得不说,我发现它比说吉斯或春天要复杂得多。也许这是由于我使用了Dropwizard,这使得访问Service定位器不那么容易。
但是,这是您可以执行的操作。
首先,您将必须获得对ServiceLocator的引用。它也必须与球衣使用的ServiceLocator相同。您可以访问它,例如:
How to get HK2 ServiceLocator in Jersey 2.12?
在示例代码中,我将使用事件侦听器,这是由于我的Dropwizard设置所致。
您现在有2个选择:向服务定位器注册命令并让注入框架处理创建,或者将ServiceLocator传递给命令以使用它。
我用Dropwizard和jersey写了一个简单的例子:
public class ViewApplication extends io.dropwizard.Application<Configuration> {
@Override
public void run(Configuration configuration, Environment environment) throws Exception {
environment.jersey().register(new ApplicationEventListener() {
@Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) {
ServiceLocator serviceLocator = ((ServletContainer) environment.getJerseyServletContainer())
.getApplicationHandler().getServiceLocator();
ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
@Override
protected void configure() {
bind(new Repository("test")).to(Repository.class);
bind(MyCommandInjected.class).to(MyCommandInjected.class);
}
});
MyCommandInjected service = serviceLocator.getService(MyCommandInjected.class);
MyCommandManual tmp = new MyCommandManual(serviceLocator);
}
}
@Override
public RequestEventListener onRequest(RequestEvent requestEvent) {
return null;
}
});
}
@Override
public void initialize(Bootstrap<Configuration> bootstrap) {
super.initialize(bootstrap);
}
public static void main(String[] args) throws Exception {
new ViewApplication().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test.yaml");
}
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public static class HelloResource {
@GET
@Path("asd")
public String test(String x) {
return "Hello";
}
}
public static class Repository {
@Inject
public Repository(String something) {
}
}
public static class MyCommandInjected {
@Inject
public MyCommandInjected(final Repository repo) {
System.out.println("Repo injected " + repo);
}
}
public static class MyCommandManual {
public MyCommandManual(final ServiceLocator sl) {
Repository service = sl.getService(Repository.class);
System.out.println("Repo found: " + service);
}
}
}
在Run方法中,我可以访问我的ServiceLocator。我在那里绑定我的课程(因此有一个如何做到这一点的例子)。您也可以选择直接在球衣上注册Binders-它们将使用正确的ServiceLocator。
2个类
MyCommandInjected
和MyCommandManual
是如何创建此命令的示例。与您相关的行可能是:
Repository service = sl.getService(Repository.class);
这会向服务定位器询问存储库的新实例。
现在,这只是一个简单的例子。与直接使用HK2相比,我更喜欢guice桥:)我发现它更易于使用且更清晰。使用guice-jersey-bridge,您可以通过guice完成所有操作,它将自动执行正确的操作。
希望能带入一些东西,
阿图尔