有什么方法可以将依赖项注入到手动创建的对象中吗?

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个类MyCommandInjectedMyCommandManual是如何创建此命令的示例。

与您相关的行可能是:

Repository service = sl.getService(Repository.class);


这会向服务定位器询问存储库的新实例。

现在,这只是一个简单的例子。与直接使用HK2相比,我更喜欢guice桥:)我发现它更易于使用且更清晰。使用guice-jersey-bridge,您可以通过guice完成所有操作,它将自动执行正确的操作。

希望能带入一些东西,

阿图尔

09-11 00:36
查看更多