Java 客户端库的Guice注入和Builder模式
我对GoogleGuice还不熟悉,我正努力思考如何在我的特定场景中使用它。我正在构建一个非常复杂的服务客户机,并且(我相信)确实需要正确实例化构建器模式。因为这个客户机最终将打包到它自己的JAR库中,所以我希望Guice在幕后处理DI。下面是我的代码的简化版本:Java 客户端库的Guice注入和Builder模式,java,dependency-injection,guice,builder-pattern,Java,Dependency Injection,Guice,Builder Pattern,我对GoogleGuice还不熟悉,我正努力思考如何在我的特定场景中使用它。我正在构建一个非常复杂的服务客户机,并且(我相信)确实需要正确实例化构建器模式。因为这个客户机最终将打包到它自己的JAR库中,所以我希望Guice在幕后处理DI。下面是我的代码的简化版本: public interface MyClient { public FizzResource getFizzResource(); public BuzzResource getBuzzResource();
public interface MyClient {
public FizzResource getFizzResource();
public BuzzResource getBuzzResource();
public FooResource getFooResource();
}
public class MyClientImpl implements MyClient {
// See below
}
public class GetFizzCommand {
// omitted for brevity
}
public class GetBuzzCommand {
// omitted for brevity
}
public class GetFooCommand {
// omitted for brevity
}
public interface FizzResource {
Fizz getFizz(Long fizzId);
}
public class FizzResourceImpl implements FizzResource {
private GetFizzCommand getFizzCommand;
@Override
Fizz getFizz(Long fizzId) {
return getFizzCommand.doGetFizz(fizzId);
}
}
public interface BuzzResource {
Buzz getBuzz(Long buzzId);
}
public class BuzzResourceImpl implements BuzzResource {
private GetBuzzCommand getBuzzCommand;
@Override
Buzz getBuzz(Long buzzId) {
return getBuzzCommand.doGetBuzz(buzzId);
}
}
public interface FooResource {
Foo getFoo(Long fooId);
}
public class FooResourceImpl implements FooResource {
private GetFooCommand getFooCommand;
@Override
Foo getFoo(Long fooId) {
return getFooCommand.doGetFoo(fooId);
}
}
因此,您可以看到层次结构/dep图如下所示:
应注入MyClient
s*ResourceImpl
- 每个
都应该注入一个*ResourceImpl
实例*命令
MyClient
impl尽可能简单:
MyClient myClient = MyClientImpl.Builder("myservice.example.org", 8080L, getWidget())
.withAuth("user", "password")
.withHttps()
.withFailureStrategy(someFailureStrategy)
// ...etc.
.build();
下面是我对MyClientImpl
及其内部构建器和my Guice模块的最佳尝试:
public class BaseClient {
private String uri;
private long port;
private Widget widget;
// ctor, getters and setters
}
public class MyClientImpl extends BaseClient implements MyClient {
@Inject
private FizzResource fizzResource;
@Inject
private BuzzResource buzzResource;
@Inject
private FooResource fooResource
public MyClientImpl(String uri, long port, Widget widget) {
super(uri, port, widget);
}
public static class Builder {
private String uri;
private long port;
private Widget widget;
Builder(String uri, long port, Widget widget) {
super();
setUri(uri);
setPort(port);
setWidget(widget);
}
// Lots of methods on the builder setting lots of MyClient-specific properties
// that I have omitted here for brevity.
MyClient build() {
Injector injector = Guice.createInjector(new MyClientModule(this));
return injector.getInstance(MyClient.class);
}
}
}
public class MyClientModule extends AbstractModule {
private MyClientImpl.Builder builder;
public MyClientModule(MyClientImpl.Builder builder) {
super();
setBuilder(builder);
}
@Override
protected void configure() {
MyClientImpl myClientImpl = new MyClientImpl(builder.getUri(), builder.getPort(), builder.getWidget());
bind(MyClient.class).toInstance(myClientImpl);
}
}
但就我的一生而言,我不知道如何/在哪里:
- 将
s绑定到*命令
s;及*ResourceImpl
- 将
s绑定到*ResourceImpl
实例MyClientImpl
有什么想法吗?现在还不完全清楚你想通过注射达到什么目的。您可能会进一步混淆这一问题,因为它涉及到建设者和您设计的其他方面。我建议您将代码拆分为一个函数,但不包括任何注入,然后通过注入(例如)单个字段来增加您的设计。现在,您的代码所显示的只是一个复杂设计的精简框架,带有没有意义的注入,并且无法运行代码并查看发生了什么。Guice在运行时运行,因此我们必须查看
main
方法,以了解应用程序代码的实际功能
下面是我上面描述的一个非常简单的例子
具有两个不同impl的接口:
public interface Service {
void useService();
}
public class FooService implements Service {
public void useService() {
System.out.println("foo service used");
}
}
public class BarService implements Service {
public void useService() {
System.out.println("bar service used");
}
}
public class ServiceUser {
Service service = new FooService(); // change impl to be used here
public static void main(String[] args) {
new ServiceUser().service.useService();
}
}
public class ServiceUserGuicified {
@Inject
Service service;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new FooServiceModule());
ServiceUserGuicified user = injector.getInstance(ServiceUserGuicified.class);
user.service.useService();
}
}
public class FooServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(FooService.class);
}
}
此界面的普通(非GUI)用户:
public interface Service {
void useService();
}
public class FooService implements Service {
public void useService() {
System.out.println("foo service used");
}
}
public class BarService implements Service {
public void useService() {
System.out.println("bar service used");
}
}
public class ServiceUser {
Service service = new FooService(); // change impl to be used here
public static void main(String[] args) {
new ServiceUser().service.useService();
}
}
public class ServiceUserGuicified {
@Inject
Service service;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new FooServiceModule());
ServiceUserGuicified user = injector.getInstance(ServiceUserGuicified.class);
user.service.useService();
}
}
public class FooServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(FooService.class);
}
}
此界面的指定用户:
public interface Service {
void useService();
}
public class FooService implements Service {
public void useService() {
System.out.println("foo service used");
}
}
public class BarService implements Service {
public void useService() {
System.out.println("bar service used");
}
}
public class ServiceUser {
Service service = new FooService(); // change impl to be used here
public static void main(String[] args) {
new ServiceUser().service.useService();
}
}
public class ServiceUserGuicified {
@Inject
Service service;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new FooServiceModule());
ServiceUserGuicified user = injector.getInstance(ServiceUserGuicified.class);
user.service.useService();
}
}
public class FooServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(FooService.class);
}
}
在Guicified版本中,impl定义在Guice模块中编码,而不是在运行时代码中编码。运行时代码包含的唯一内容是创建喷油器时模块的使用情况。您可以为酒吧服务创建一个新模块,并使用该模块创建一个注射器,或者您可以更改主服务模块中的绑定
一旦您了解了上面发生的事情,您就应该能够通过在希望Guice注入的每个实例上重复这些概念来解决自己代码中的任何问题。我认为您可能会对绑定的目的感到困惑。绑定有助于GUI确定如何为您提供类型的实例,例如实例化接口的哪个实现。不需要将
命令
绑定到资源
,也没有意义,因为它们不属于同一类型层次结构。此外,您没有在任何地方插入命令,因此不需要对其进行绑定。另外,你的MyClientModule
正在做一些奇怪的事情。在configure方法中,它试图构造参数为null的内容。我不确定您的意图是什么,因为我没有看到MyClient
@Inject
ed。旁注:@Injected
不是Guice注释。感谢@111(+2),我更正了我的@Injected
注释(很好)。然而,我仍然无法透过这里的树木看到森林。一个关于如何修复我的构建器/模块组合的代码示例将有助于我将事情联系在一起。再次感谢!