0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Теги: dependency injection, di, spring, java, циклическая зависимость, di через параметры конструктора, di через поля, @postconstruct, nullpointerexception, зависимости в бин, spring context, di через сеттеры</p>
1
<p>Теги: dependency injection, di, spring, java, циклическая зависимость, di через параметры конструктора, di через поля, @postconstruct, nullpointerexception, зависимости в бин, spring context, di через сеттеры</p>
2
<p>Dependency Injection в Spring можно осуществлять различными способами. Рассмотрим плюсы и минусы данных подходов.</p>
2
<p>Dependency Injection в Spring можно осуществлять различными способами. Рассмотрим плюсы и минусы данных подходов.</p>
3
<h2>Например, рассмотрим DI через параметры конструктора</h2>
3
<h2>Например, рассмотрим DI через параметры конструктора</h2>
4
@Service public class MyService { private Dependency dependency; @Autowired public MyService(Dependency dependency) { this.dependency = dependency; } }<p>Данный подход является рекомендованным. Разберёмся с некоторыми ситуациями, где DI через параметры конструктора может выглядеть не самым лучшим образом, и выясним, причины этого:</p>
4
@Service public class MyService { private Dependency dependency; @Autowired public MyService(Dependency dependency) { this.dependency = dependency; } }<p>Данный подход является рекомендованным. Разберёмся с некоторыми ситуациями, где DI через параметры конструктора может выглядеть не самым лучшим образом, и выясним, причины этого:</p>
5
<p><b>Чуешь, чем пахнет?</b>Появляется большое число параметров конструктора, что является "запахом плохого кода". Если для создания бина требуется множество зависимостей, то DI через конструктор, как ни странно, ни при чём. Если в классе большое число зависимостей, то это говорит, скорее о неправильном дизайне самого сервиса.</p>
5
<p><b>Чуешь, чем пахнет?</b>Появляется большое число параметров конструктора, что является "запахом плохого кода". Если для создания бина требуется множество зависимостей, то DI через конструктор, как ни странно, ни при чём. Если в классе большое число зависимостей, то это говорит, скорее о неправильном дизайне самого сервиса.</p>
6
<p><b>Как пони по кругу</b>Если между классами есть циклическая зависимость, то DI через конструктор не получится организовать. Действительно, это так, но если появилась циклическая зависимость между классами, то это, скорее, неправильное разделение ответственности между сервисами.</p>
6
<p><b>Как пони по кругу</b>Если между классами есть циклическая зависимость, то DI через конструктор не получится организовать. Действительно, это так, но если появилась циклическая зависимость между классами, то это, скорее, неправильное разделение ответственности между сервисами.</p>
7
<p><b>У DI через параметры конструктора, есть безусловные плюсы:</b></p>
7
<p><b>У DI через параметры конструктора, есть безусловные плюсы:</b></p>
8
<li>в любой момент времени вы всегда получите готовый к работе класс со всеми зависимостями;</li>
8
<li>в любой момент времени вы всегда получите готовый к работе класс со всеми зависимостями;</li>
9
<li>данные классы можно просто тестировать как обычные Java-классы и без поднятия контекста для тестирования;</li>
9
<li>данные классы можно просто тестировать как обычные Java-классы и без поднятия контекста для тестирования;</li>
10
<li>в unit-тестах вы не сможете забыть добавить какую-либо зависимость, так как она будет требоваться на уровне компиляции.</li>
10
<li>в unit-тестах вы не сможете забыть добавить какую-либо зависимость, так как она будет требоваться на уровне компиляции.</li>
11
<p>С циклическими зависимостями можно, в частности, бороться с помощью</p>
11
<p>С циклическими зависимостями можно, в частности, бороться с помощью</p>
12
<h2>DI через поля:</h2>
12
<h2>DI через поля:</h2>
13
@Service public class MyService { @Autowired private Dependency dependency; }<p>Несмотря на действительно минимальное количество кода, этот подход обладает одним большим недостатком. Данный класс нельзя просто протестировать, не поднимая Spring Context. Если для контроллеров и других классов в любом случае придётся его поднимать, то для бизнес-сервисов это излишне.</p>
13
@Service public class MyService { @Autowired private Dependency dependency; }<p>Несмотря на действительно минимальное количество кода, этот подход обладает одним большим недостатком. Данный класс нельзя просто протестировать, не поднимая Spring Context. Если для контроллеров и других классов в любом случае придётся его поднимать, то для бизнес-сервисов это излишне.</p>
14
<h2>Ну и DI через сеттеры</h2>
14
<h2>Ну и DI через сеттеры</h2>
15
@Service public class MyService { private Dependency dependency; @Autowired public void setDependency(Dpendency dependency) { this.dependency = dependency; } }<p>В данном случае тестировать эти классы почти так же просто, как и в случае DI через параметры конструктора. Но в тестах очень легко забыть проставить зависимость, не вызвав свежедобавленный сеттер.</p>
15
@Service public class MyService { private Dependency dependency; @Autowired public void setDependency(Dpendency dependency) { this.dependency = dependency; } }<p>В данном случае тестировать эти классы почти так же просто, как и в случае DI через параметры конструктора. Но в тестах очень легко забыть проставить зависимость, не вызвав свежедобавленный сеттер.</p>
16
<p>Этот способ обладает одним серьёзным недостатком: до того момента, как Spring проставит все зависимости в бин, экземпляр класса находится в некорректном состоянии. И обращение к зависимостям может привести к<b>NullPointerException</b>. Для того, чтобы сделать какие-то действия после того, как все зависимости будут инъектированы, используют аннотацию<b>@PostConstruct</b>:</p>
16
<p>Этот способ обладает одним серьёзным недостатком: до того момента, как Spring проставит все зависимости в бин, экземпляр класса находится в некорректном состоянии. И обращение к зависимостям может привести к<b>NullPointerException</b>. Для того, чтобы сделать какие-то действия после того, как все зависимости будут инъектированы, используют аннотацию<b>@PostConstruct</b>:</p>
17
@Service public class MyService { private Dependency dependency;<p>@Autowired public void setDependency(Dpendency dependency) { this.dependency = dependency; }</p>
17
@Service public class MyService { private Dependency dependency;<p>@Autowired public void setDependency(Dpendency dependency) { this.dependency = dependency; }</p>
18
<p>@PostConstruct public void init() { this.dependency.doSomething(); } }</p>
18
<p>@PostConstruct public void init() { this.dependency.doSomething(); } }</p>
19
<p><i>Остались вопросы? Задавайте в комментариях!</i></p>
19
<p><i>Остались вопросы? Задавайте в комментариях!</i></p>
20
20