Jersey HK2 注入手动创建的对象
Jersey HK2 injection in manually created objects
有什么方法可以将依赖项注入到手动创建的对象中吗?
public class MyCommand {
@Inject Repository repository;
}
public Repository {
@Inject EntityManager em;
}
MyCommand command = new MyCommand();
存储库已正确注册 jersey ResourceConfig,并且可以注入通过 CDI 容器创建的对象,例如资源 class。
但是由于我自己创建了命令,@Inject 注释被忽略了。
有没有办法在@Inject 和@Context 旁边注册一个class?
像 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);
}
}
您可以使用 ServiceLocator 的 inject 方法来注入已创建的对象。 ServiceLocator 是 HK2 的基本注册表,应该在您的资源中可用。
正如 jwells 指出的那样 - HK2 是一个注入框架 :)
我花了一些时间研究它 - 我不得不说,我发现它比说 guice 或 spring 复杂得多。也许这是因为我使用 Dropwizard,这使得访问服务定位器变得不那么容易。
但是,您可以按照以下方法进行操作。
首先,您必须获得对 ServiceLocator 的引用。它也必须与 jersey 正在使用的 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);
}
}
}
在 运行 方法中,我可以访问我的 ServiceLocator。我在那里绑定了我的 类 (所以有一个如何做到这一点的例子)。您也可以直接向 jersey 注册 Binders——它们将使用正确的 ServiceLocator。
2 类 MyCommandInjected
和 MyCommandManual
是如何创建此命令的示例。
与您相关的行可能是:
Repository service = sl.getService(Repository.class);
这向服务定位器请求存储库的新实例。
现在,这只是一个简单的例子。与直接使用 HK2 相比,我更喜欢 guice 桥 :) 我发现它更易于使用且更清晰。使用 guice-jersey-bridge 你可以通过 guice 做任何事情,它会自动做正确的事情。
希望能带来一些内在,
阿图尔
有什么方法可以将依赖项注入到手动创建的对象中吗?
public class MyCommand {
@Inject Repository repository;
}
public Repository {
@Inject EntityManager em;
}
MyCommand command = new MyCommand();
存储库已正确注册 jersey ResourceConfig,并且可以注入通过 CDI 容器创建的对象,例如资源 class。
但是由于我自己创建了命令,@Inject 注释被忽略了。
有没有办法在@Inject 和@Context 旁边注册一个class? 像 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);
}
}
您可以使用 ServiceLocator 的 inject 方法来注入已创建的对象。 ServiceLocator 是 HK2 的基本注册表,应该在您的资源中可用。
正如 jwells 指出的那样 - HK2 是一个注入框架 :)
我花了一些时间研究它 - 我不得不说,我发现它比说 guice 或 spring 复杂得多。也许这是因为我使用 Dropwizard,这使得访问服务定位器变得不那么容易。
但是,您可以按照以下方法进行操作。
首先,您必须获得对 ServiceLocator 的引用。它也必须与 jersey 正在使用的 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);
}
}
}
在 运行 方法中,我可以访问我的 ServiceLocator。我在那里绑定了我的 类 (所以有一个如何做到这一点的例子)。您也可以直接向 jersey 注册 Binders——它们将使用正确的 ServiceLocator。
2 类 MyCommandInjected
和 MyCommandManual
是如何创建此命令的示例。
与您相关的行可能是:
Repository service = sl.getService(Repository.class);
这向服务定位器请求存储库的新实例。
现在,这只是一个简单的例子。与直接使用 HK2 相比,我更喜欢 guice 桥 :) 我发现它更易于使用且更清晰。使用 guice-jersey-bridge 你可以通过 guice 做任何事情,它会自动做正确的事情。
希望能带来一些内在,
阿图尔