首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >有没有更方便的方法来提供(绑定到guice模块)已经创建的实例?

有没有更方便的方法来提供(绑定到guice模块)已经创建的实例?
EN

Stack Overflow用户
提问于 2021-01-06 03:24:41
回答 3查看 45关注 0票数 0

我在桌面应用程序中使用Guice,并希望为服务添加通用绑定。这些服务是单例(绑定)实例,在应用程序启动时手动创建。我只使用IoC容器来创建图形用户界面。我手动创建这些服务,因为在启动过程中我想要发布进度。

由于GUI使用这些服务,因此它们必须绑定到guice GUI模块。

如果不为每个类使用一个带有setter和getter的类,我想不出一种绑定它们的方法。

假设我有CarService和EngineService。我现在所拥有的是:

代码语言:javascript
运行
复制
public class GuiceServices {

    public static void main(String[] args) {
        ServicesModule servicesModule = new ServicesModule();

        CarService carService = new CarServiceImpl();
        servicesModule.setCarService(carService);
        System.out.println("progress: 50%");

        EngineService engineService = new EngineServiceImpl();
        servicesModule.setEngineService(engineService);
        System.out.println("Progress: 100%");

        Injector i = Guice.createInjector(new GuiModule(), servicesModule);
        i.getInstance(MainView.class).show();
    }

    class ServicesModule extends AbstractModule {
        private CarService carService;
        private EngineService engineService;
        @Override
        protected void configure() {
            
        }
        
        public void setCarService(CarService carService) {
            this.carService = carService;
        }
        
        public void setEngineService(EngineService engineService) {
            this.engineService = engineService;
        }
        
        @Provides
        public CarService getCarService() {
            return carService;
        }
        
        @Provides
        public EngineService getEngineService() {
            return engineService;
        }
    }
}

但这是一种痛苦,因为这些服务很多。

有没有办法避免这种情况?

理想情况下,地图更方便。类似于:

代码语言:javascript
运行
复制
public class GuiceServices {

    public static void main(String[] args) {
        ServicesMap servicesMap = new ServicesMap();

        CarService carService = new CarServiceImpl();
        servicesMap.put(CarService.class, carService);
        System.out.println("progress: 50%");

        EngineService engineService = new EngineServiceImpl();
        servicesMap.put(EngineService.class, engineService);
        System.out.println("Progress: 100%");

        Injector i = Guice.createInjector(new GuiModule(), new ServicesModule(servicesMap));
        i.getInstance(MainView.class).show();
    }

    class ServicesModule extends AbstractModule {
        private ServicesMap services;
        public SerrvicesModule(ServicesMap services) {
            this.services = services;
        }
        @Override
        protected void configure() {
            for (Class<?> serviceType : services.keySet())
            {
                bind(serviceType).toInstance(services.get(serviceType));
            }
        }       
    }
}

但是我找不到一种方法来创建和实现这个"servicesMap“。因为bind方法返回一个泛型构建器。Guice (或Guava)是否为这种情况提供了一些东西?

我知道我可以使用Guice创建服务,并使用注入/类型侦听器发布进度,但是包含所有服务的业务包(模块)没有javax.inject依赖。另外,这些服务的创建很复杂,因此最好是手动创建。此外,在Guice模块中发布GUI进度听起来太复杂了,而不是在Guice模块中。

那么,有没有办法呢?与上述代码片段中的System.out.println不同,还有一个手动创建的闪屏。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-01-08 22:19:33

实际上是我自己实现的。

我所做的是在模块中创建一个List<Consumer<Binder>>,然后在configure()方法中组合它们。

代码语言:javascript
运行
复制
class ServicesModule extends AbstractModule {
    private List<Consumer<Binder>> consumers = new ArrayList<>();

    ServicesModule() {
    }

    @Override
    protected void configure() {
        consumers.forEach(c -> c.accept(binder()));
    }

    <T> void putService(Class<T> clazz, T instance) {
        consumers.add(t -> t.bind(clazz).toInstance(instance));
    }

}

然后,在应用程序启动期间,我可以逐渐提供服务依赖关系:

代码语言:javascript
运行
复制
public static void main(String[] args) {
    ServicesModule services = new ServicesModule();
    
    CarService carService = new CarServiceImpl();
    serviceModule.putService(CarService.class, carService);
    publishProgress(35);
    
    EngineService engineService = new EngineServiceImpl(carService);
    serviceModule.putService(EngineService.class, engineService);
    publishProgres(50);
    //...
    Injector i = Guice.createInjector(new GuiModule(), services);
    i.getInstance(MainView.class).show();
}
票数 -1
EN

Stack Overflow用户

发布于 2021-01-06 15:52:30

只需将构建每个服务impl的代码移到相应服务接口的@Provides方法的主体中即可。您提到希望这些方法是单例的,所以您还需要用@Singleton注释provider方法。

至于地图,你可以用Multibinder来做类似的事情,但在推荐之前,我想更好地了解你的设计。

票数 0
EN

Stack Overflow用户

发布于 2021-01-09 08:27:02

您提出的答案需要了解要在这些类之外传播的服务实现类的依赖关系。依赖注入的整个思想是封装实现依赖。例如,只有EngineServiceImpl应该知道它依赖于CarService。封装使您的代码更容易推理和测试。

代码语言:javascript
运行
复制
class ServiceModule extends AbstractModule {
  protected void configure() {
    bind(CarService.class).to(CarServiceImpl.class).in(Singleton.class);
    bind(EngineService.class).to(EngineServiceImpl.class).in(Singleton.class);
  }
}

class CarServiceImpl implements CarService {
  @Inject
  CarServiceImpl() {} // Not necessary, but adds clarity

  // ...
}

class EngineServiceImpl implements EngineService {
  private final CarService carService;

  @Inject
  EngineServiceImpl(CarService carService) {
    this.carService = carService;
  }

  // ...
}

class Main {
  public static void main(String[] args) {
    // I find it clearer to get the starting-point class instance from the injector
    // creation chain, then operate on that instance.
    MainView mainView = 
        Guice.createInjector(new GuiModule(), new ServiceModule())
            .getInstance(MainView.class);
    mainView.show();
  }
}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65585288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档