Еще одна статья о DI в Spring Boot


Как сказал один мудрец: вечно смотреть можно на три вещи: как течет вода, как горит огонь и как кто-то пишет очередную стать о DI в Spring Boot. Сегодня я сделаю попытку коротко описать всю эту петрушку.

DI (Dependency Injection, внедрение зависимости) — процесс при котором построение одного объекта, предоставляется внешнему объекту. Или точнее это то место, где зависимость будет внедрена другим объектом. Понятнее будет на примере. Пусть у нас есть класс «Автомобиль» у него есть поле класса «Двигатель». Место где «Двигатель» будет инициализирован в «Автомобиле» и будет внедрением зависимости.

В Spring Boot существует 4 типа DI:

  1. Как поле класса
  2. Как приватное поле класса (прочитали что так можно делать DI, теперь забудьте — способ 2 ЗЛО!)
  3. С помощью setter
  4. С помощью конструктора

DI с помощью «сеттера» до сих пор остается местом споров. Это связано с другой особенностью Spring Boot — Ioc (Inversion of Controll, инверсия контроля). IoC — передача управления. Обычно программист сам решает когда вызывать ту или иную процедуру, делать DI и т.п. В Spring Boot — это делает IoC — инициализация и вызовы процедур в Runtime. Получается, что используя DI с помощью «сеттера» вы не можете знать в какой именно момент вы зависимость будет внедрена.

DI как поле класса используется редко по причине нарушения инкапсуляции, ведь внедряемое поле должно быть помечено как public.

DI с помощью конструктора — наиболее предпочтительный способ осуществления DI. Связывание будет осуществлено в момент создания объекта и вы точно будете знать когда именно IoC осуществит вызов.

В Spring Boot в месте, где будет осуществлена инъекция необходимо ставить аннотацию @Autowired (автосвязывание). Однако, если вы используете DI с помощью конструктора использовать эту аннотацию необязательно.

Ниже я приведу пример каждого способа DI кроме 2, ведь, мы на светлой стороне силы, так?

DI как поле класса

@Controller
public class PropertyInjectedController {

    @Autowired
    public GreetingServiceImpl greetingService;

    public String sayHello(){
        return greetingService.sayGreeting();
    }

}

Недостатки:

  1. Публичное поле
  2. Нельзя указать интерфейс, только конкретную реализацию. Использовать DI интерфейсов это хорошая практика, дающая много преимуществ и открывающая перед вами другие инструменты Spring Boot для внедрения зависимостей, но об этом как-нибудь в другой раз.

DI как сеттер

@Controller
public class SetterInjectedController {
    private GreetingService greetingService;

    public String sayHello(){
        return greetingService.sayGreeting();
    }

    @Autowired
    public void setGreetingService(GreetingService greetingService) {
        this.greetingService = greetingService;
    }
}

Главный недостаток описан выше.

DI как конструктор

@Controller
public class ConstructorInjectedController {

    private GreetingService greetingService;

    @Autowired
    public ConstructorInjectedController(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    public String sayHello(){
        return greetingService.sayGreeting();
    }
}

Какой из способов использовать — решать вам. Главное, чтобы это был DI с помощью конструктора.
Tags:
java, spring boot, di

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.