Guice - Ограничения полевых инъекций

1

Предположим, что у нас есть класс, называемый Bean, который зависит от другого класса, называемого Service, используя Fields Injection, и мы не можем изменить код этих классов. Другой класс (App) использует Provider для создания новых экземпляров Bean, когда захочет, и мы можем изменять код в этих классах.

Поскольку в методе Provider get() новый экземпляр создается с использованием new оператора, невозможно вставить Service в Bean, поэтому экземпляр Bean будет неполным (поле Service будет равно null).

Одним из способов обойти эту проблему было бы Injector в Провайдере и вызвать метод injector.injectMembers() в методе get() в новом экземпляре.

Пример кода следующий (я избегал использования интерфейсов, чтобы сделать код короче).

class Bean {
    @Inject private Service service;

    public Bean() {
    }

    public void bar() {
        this.service.foo();
    }
}

class Service {

    public void foo() {
        System.out.println("foo");
    }
}

class App {
    @Inject private Provider<Bean> beanProvider;

    public App() {
    }

    public void run() {
        this.beanProvider.get().bar();
    }
}

class BeanProvider implements Provider<Bean> {
    @Inject Injector injector;

    public Bean get() {
        Bean mybean = new Bean();
        this.injector.injectMembers(mybean);

        return mybean;
    }
}

// A simple module to bind the classes
class MyModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Service.class);
        bind(Bean.class).toProvider(BeanProvider.class);
        bind(App.class);
    }
}


public static void main(String[] args) {
    Injector injector = Guice.createInjector(new MyModule());
    injector.getInstance(App.class).run();
}

Другой способ состоял бы в том, чтобы изменить Bean на использование Construction Injection, но, как я сказал, допустим, что мы не можем этого сделать.

Я знаю, что большинство людей утверждают, что следует избегать инъекции Injector, поскольку он нарушает всю философию DI, поскольку инжектор должен использоваться только в точке входа приложения и нигде больше, но поскольку Guice предлагает различные способы использования DI в приложении, например, "Инъекция поля", могут возникать ситуации, подобные описанным. Кроме того, я видел, что Field Injection используется довольно часто в нескольких проектах, поэтому такие случаи часто бывают.

Итак, существует ли "более чистый" способ избежать инъекции Injector в описанной проблеме?

Теги:
dependency-injection
guice
guice-3

1 ответ

4

Похоже, что это не должно быть проблемой для вашего модуля. Не похоже, что вам необходимо создать провайдера вообще.

Связывания, которые вы установили в своем модуле, должны привести к тому, что Service будет введен в Bean, где вам это нужно. Таким образом, вы должны просто заменить декларацию поставщика в приложении с помощью инъекции Bean.

class App {
     @Inject private Bean beanObject;

     public App() {
     }

     public void run() {
         this.beanObject.bar();
     }
}

// A simple module to bind the classes
class MyModule extends AbstractModule {
    @Override
    protected void configure() {
        //bind this to whatever you want to inject into Bean...
        bind(Service.class); 
        bind(Bean.class);
        bind(App.class);
    }
}

Если это не сработает для вас, можете ли вы уточнить, что вы пытаетесь сделать и почему вам нужен провайдер?

  • 0
    Спасибо за ваш ответ. Причина, по которой я хочу использовать Provider вместо простого внедрения, заключается в том, что в некоторых случаях класс Bean может иметь более узкую область действия, чем класс App (возможно, имена сейчас сбивают с толку, но суть вопроса требует, по какой-то причине, использования Провайдер)
  • 0
    Хм ... если требуется использование провайдера, то я не вижу большого пути обхода с инжектором ... (если не считать написания собственного кусочка отражающего бина-популятора и повторной реализации поведения самого инжектора) ).
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню