Ін’єкція конструктора навесні з Ломбоком

1. Вступ

Ломбок - надзвичайно корисна бібліотека, яка долає шаблонний код. Якщо ви ще не знайомі з ним, настійно рекомендую поглянути на попередній підручник - Вступ до проекту Lombok.

У цій статті ми продемонструємо його зручність у поєднанні з інжекцією залежностей на основі конструктора Spring .

2. Інжекція залежностей на основі конструктора

Хороший спосіб зв’язати залежності навесні за допомогою c onstructor Dependency Injection . Цей підхід змушує нас явно передавати залежності компонента конструктору.

На відміну від польової інжекції залежності , вона також забезпечує ряд переваг:

  • немає необхідності створювати компонент конфігурації, специфічний для тесту - залежності явно вводяться в конструктор
  • послідовний дизайн - усі необхідні залежності підкреслюються та доглядаються за визначенням конструктора
  • прості модульні тести - зменшення накладних витрат Spring Framework
  • відновлена ​​свобода використання кінцевих ключових слів

Однак через необхідність написання конструктора він використовує для створення значно більшої бази коду. Розглянемо два приклади GreetingService та FarewellService:

@Component public class GreetingService { @Autowired private Translator translator; public String produce() { return translator.translate("hello"); } }
@Component public class FarewellService { private final Translator translator; public FarewellService(Translator translator) { this.translator = translator; } public String produce() { return translator.translate("bye"); } }

В основному обидва компоненти виконують одне і те ж - вони викликають настроюваний перекладач із словом, що відповідає конкретній задачі.

Другий варіант, однак, набагато затуманеніший через шаблон конструктора, який насправді не приносить значення коду.

У найновішому випуску Spring, його конструктор не потрібно коментувати анотацією @Autowired .

3. Ін’єкція конструктора з Ломбоком

За допомогою Lombok можна створити конструктор або для всіх полів класу (з @AllArgsConstructor ), або для всіх полів кінцевого класу (з @RequiredArgsConstructor ). Більше того, якщо вам все ще потрібен порожній конструктор, ви можете додати додаткову анотацію @NoArgsConstructor .

Давайте створимо третій компонент, аналог попередніх двох:

@Component @RequiredArgsConstructor public class ThankingService { private final Translator translator; public String produce() { return translator.translate("thank you"); } }

Вищенаведена анотація змусить Lombok створити для нас конструктор:

@Component public class ThankingService { private final Translator translator; public String thank() { return translator.translate("thank you"); } /* Generated by Lombok */ public ThankingService(Translator translator) { this.translator = translator; } }

4. Кілька конструкторів

Конструктор не повинен бути анотований, доки в компоненті є лише один, і Spring може однозначно вибрати його як правильний для створення нового об'єкта. Як тільки їх буде більше, вам також потрібно позначити той, який буде використовуватися контейнером IoC.

Розглянемо приклад ApologizeService :

@Component @RequiredArgsConstructor public class ApologizeService { private final Translator translator; private final String message; @Autowired public ApologizeService(Translator translator) { this(translator, "sorry"); } public String produce() { return translator.translate(message); } }

Вищезазначений компонент можна додатково налаштувати з полем повідомлення, яке не може змінюватися після створення компонента (звідси відсутність сеттера ). Таким чином, це вимагало від нас двох конструкторів - одного з повною конфігурацією, а іншого з неявним значенням повідомлення за замовчуванням .

Якщо до одного з конструкторів не додано @Autowired , @Inject або @Resource , Spring видасть помилку:

Failed to instantiate [...]: No default constructor found;

Якщо ми хочемо , щоб анотувати Lombok- згенерований конструктор, ми повинні пройти анотацію з onConstructor параметром @AllArgsConstructor :

@Component @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class ApologizeService { // ... }

Параметр onConstructor приймає масив анотацій (або окрему анотацію, як у цьому конкретному прикладі), які повинні бути розміщені в створеному конструкторі. Ідіома подвійного підкреслення була введена через проблеми зворотної сумісності. Згідно з документацією:

Причина дивного синтаксису полягає в тому, що ця функція працює в компіляторах javac 7; @__тип є посиланням на анотацію до типу анотацій __(подвійне підкреслення) , яка на самому ділі не існує; це змушує javac 7 затримати переривання процесу компіляції через помилку, оскільки цілком можливо, що процесор анотацій згодом створить __тип.

5. Підсумок

У цьому підручнику ми показали, що немає потреби надавати перевагу польовому DI замість DI на основі конструктора з точки зору збільшення коду шаблону.

Завдяки Lombok можна автоматизувати генерацію загального коду без впливу на продуктивність на час роботи, скорочуючи довгий, затемнюючий код до використання однорядкової анотації.

Код, використаний під час підручника, доступний на GitHub.