Поиск…


замечания

Исходный код для больших программных приложений обычно организован в несколько блоков. Определение единицы обычно зависит от используемого языка программирования. Например, код, написанный на языке процедурного программирования (например, C), организован в functions или procedures . Аналогично, код на объектно-ориентированном языке программирования (например, Java, Scala и C #) организован в classes , interfaces и так далее. Эти единицы организации кода можно рассматривать как отдельные единицы, составляющие общее программное приложение.

Когда приложения имеют несколько блоков, межзависимые отношения между этими единицами возникают, когда одному устройству приходится использовать других для выполнения своих функций. Зависимые единицы могут считаться consumers и подразделениями, от которых они зависят, в качестве providers определенных функций.

Самый простой подход к программированию заключается в том, чтобы потребители полностью контролировали поток программного приложения, решая, какие поставщики следует создавать, использовать и уничтожать в каких точках общего выполнения приложения. Говорят, что потребители имеют полный контроль над поставщиками во время потока выполнения, которые являются dependencies для потребителей. В случае, если у поставщиков есть свои зависимости, потребителям, возможно, придется беспокоиться о том, как провайдеры должны быть инициализированы (и выпущены), что делает поток управления все более и более сложным по мере увеличения количества единиц в программном обеспечении. Этот подход также увеличивает связь между блоками, что делает все более трудным изменять отдельные единицы, не беспокоясь о нарушении других частей программного обеспечения.

Inversion of Control (IoC) - это принцип разработки, который защищает аутсорсинг от потоков управления, таких как обнаружение единиц, создание экземпляров и уничтожение, независимо от потребителей и поставщиков. Основополагающим принципом IoC является развязка потребителей и поставщиков, освобождение программных единиц от необходимости беспокоиться об обнаружении, создании и очистке их зависимостей, а также позволяет подразделениям сосредоточиться на своей собственной функциональности. Эта развязка помогает поддерживать расширяемость программного обеспечения.

Инъекция зависимостей является одним из способов реализации инверсии принципа управления, при котором экземпляры зависимостей (поставщиков) вводятся в программный блок (потребитель) вместо потребителя, который должен найти и создать экземпляр.

Spring Framework содержит модуль ввода зависимостей в своем ядре, который позволяет Spring-управляемым компонентам быть введенными в другие управляемые Spring бобы в качестве зависимостей.

Внедрение зависимости вручную через конфигурацию XML

Рассмотрим следующие классы Java:

class Foo {
  private Bar bar;

  public void foo() {
    bar.baz();
  }
}

Как видно, класс Foo требует вызова метода baz на экземпляр другого класса Bar чтобы его метод foo успешно работал. Bar как говорят, является зависимостью от Foo поскольку Foo не может работать корректно без экземпляра Bar .

Впрыск конструктора

При использовании конфигурации XML для Spring Framework для определения управляемых Spring бобы, bean типа Foo можно настроить следующим образом:

<bean class="Foo">
  <constructor-arg>
    <bean class="Bar" />
  </constructor-arg>
</bean>

или, альтернативно (более подробный):

<bean id="bar" class="bar" />

<bean class="Foo">
  <constructor-arg ref="bar" />
</bean>

В обоих случаях Spring Framework сначала создает экземпляр Bar и injects его в экземпляр Foo . В этом примере предполагается, что класс Foo имеет конструктор, который может принимать экземпляр Bar в качестве параметра, то есть:

class Foo {
  private Bar bar;

  public Foo(Bar bar) { this.bar = bar; }
}

Этот стиль известен как инъекция конструктора, потому что зависимость (экземпляр Bar ) вводится через конструктор класса.

Впрыск недвижимости

Другой вариант, чтобы ввести зависимость Bar в Foo :

<bean class="Foo">
  <property name="bar">
    <bean class="Bar" />
  </property>
</bean>

или, альтернативно (более подробный):

<bean id="bar" class="bar" />

<bean class="Foo">
  <property name="bar" ref="bar" />
</bean>

Это требует, чтобы класс Foo имел метод setter, который принимает экземпляр Bar , например:

class Foo {
  private Bar bar;

  public void setBar(Bar bar) { this.bar = bar; }
}

Внедрение зависимостей вручную через конфигурацию Java

Те же примеры, что и выше, с конфигурацией XML, можно переписать с конфигурацией Java следующим образом.

Впрыск конструктора

@Configuration
class AppConfig {
  @Bean
  public Bar bar() { return new Bar(); }

  @Bean
  public Foo foo() { return new Foo(bar()); }
}

Впрыск недвижимости

@Configuration
class AppConfig {
  @Bean
  public Bar bar() { return new Bar(); }

  @Bean
  public Foo foo() {
    Foo foo = new Foo();
    foo.setBar(bar());

    return foo;
  }
}

Автоустановка зависимости через конфигурацию XML

Зависимости могут быть автообновлены при использовании функции проверки компонентов платформы Spring. Для работы автоустройства необходимо выполнить следующую конфигурацию XML:

<context:annotation-config/>
<context:component-scan base-package="[base package]"/>

где base-package - это полностью квалифицированный пакет Java, в котором Spring должен выполнять проверку компонентов.

Впрыск конструктора

Зависимости могут быть введены через конструктор классов следующим образом:

@Component
class Bar { ... }

@Component
class Foo {
  private Bar bar;

  @Autowired
  public Foo(Bar bar) { this.bar = bar; }
}

Здесь @Autowired представляет собой аннотацию, специфичную для Spring. Spring также поддерживает JSR-299, чтобы обеспечить переносимость приложений к другим основанным на Java платформам инъекций зависимостей. Это позволяет @Autowired заменяться на @Inject как:

@Component
class Foo {
  private Bar bar;

  @Inject
  public Foo(Bar bar) { this.bar = bar; }
}

Впрыск недвижимости

Зависимости также можно вводить с использованием методов сеттера следующим образом:

@Component
class Foo {
  private Bar bar;

  @Autowired
  public void setBar(Bar bar) { this.bar = bar; }
}

Полевая инъекция

Autowiring также позволяет инициализировать поля внутри экземпляров класса напрямую, а именно:

@Component
class Foo {
  @Autowired
  private Bar bar;
}

Для весенних версий 4.1+ можно использовать Дополнительно для дополнительных зависимостей.

@Component
class Foo {

    @Autowired
    private Optional<Bar> bar;
}

Тот же подход может быть использован для конструктора DI.

@Component
class Foo {
    private Optional<Bar> bar;

    @Autowired
    Foo(Optional<Bar> bar) {
        this.bar = bar;
    }
}

Автоподключение зависимости через конфигурацию Java

Встраивание конструктора через конфигурацию Java также может использовать автоподключение, например:

@Configuration
class AppConfig {
  @Bean
  public Bar bar() { return new Bar(); }

  @Bean
  public Foo foo(Bar bar) { return new Foo(bar); }
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow