java—是否有更方便的方法来提供(绑定到guice模块)已经创建的示例?

j2cgzkjk  于 2021-06-26  发布在  Java
关注(0)|答案(3)|浏览(274)

我在桌面应用程序中使用guice,并希望为服务添加通用绑定。这些服务是单例(绑定)示例,在应用程序启动期间手动创建。我只使用ioc容器来创建gui。我手动创建这些服务,因为在启动期间我想发布进度。
由于gui使用这些服务,它们必须绑定到guicegui模块。
如果不为每个类使用一个带有setter和getter的类,我想不出一种绑定它们的方法。
假设我有汽车服务和引擎服务。我现在得到的是:

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;
        }
    }
}

但这是一种痛苦,因为这些服务是大量的。
有没有办法避免这种情况?
理想情况下,Map更方便。比如:

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创建服务,并使用injection/type侦听器发布进度,但是包含所有服务的业务包(模块)没有javax.injecte依赖关系。另外,这些服务的创建非常复杂,因此最好手动创建。另外,在guice模块中发布gui进度听起来太复杂了,不适合在guice模块中发布。
那么,有办法吗?而不是 System.out.println 在上面的代码片段中,还有一个手动创建的启动屏幕。

txu3uszq

txu3uszq1#

我自己也做到了。
我所做的就是创造一个 List<Consumer<Binder>> 然后把它们放进去 configure() 方法。

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));
    }

}

然后,在应用程序启动过程中,我可以逐步提供服务依赖项:

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();
}
nue99wik

nue99wik2#

您建议的答案需要了解要分布在这些类之外的serviceinpl类的依赖关系。依赖注入的整个思想是封装实现依赖。例如,仅 EngineServiceImpl 应该知道这取决于 CarService . 封装使代码更易于推理和测试。

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();
  }
}
ntjbwcob

ntjbwcob3#

只需将构建每个service impl的代码移到@provides方法的主体中,以用于相应的服务接口。您提到希望这些方法是单例的,所以您还希望用@singleton注解提供者方法。
至于Map,你可以用多活页夹做类似的事情,但我想在推荐之前更好地理解你的设计。

相关问题