Варианты DI в Spring
Dependency Injection в Spring можно осуществлять различными способами. Рассмотрим плюсы и минусы данных подходов.
Например, рассмотрим DI через параметры конструктора
@Service public class MyService { private Dependency dependency; @Autowired public MyService(Dependency dependency) { this.dependency = dependency; } }
Чуешь, чем пахнет?
Появляется большое число параметров конструктора, что является «запахом плохого кода». Если для создания бина требуется множество зависимостей, то DI через конструктор, как ни странно, ни при чём. Если в классе большое число зависимостей, то это говорит, скорее о неправильном дизайне самого сервиса.
Как пони по кругу
Если между классами есть циклическая зависимость, то DI через конструктор не получится организовать. Действительно, это так, но если появилась циклическая зависимость между классами, то это, скорее, неправильное разделение ответственности между сервисами.
У DI через параметры конструктора, есть безусловные плюсы:
С циклическими зависимостями можно, в частности, бороться с помощью
DI через поля:
@Service public class MyService { @Autowired private Dependency dependency; }
Ну и DI через сеттеры
@Service public class MyService { private Dependency dependency; @Autowired public void setDependency(Dpendency dependency) { this.dependency = dependency; } }
Этот способ обладает одним серьёзным недостатком: до того момента, как Spring проставит все зависимости в бин, экземпляр класса находится в некорректном состоянии. И обращение к зависимостям может привести к NullPointerException. Для того, чтобы сделать какие-то действия после того, как все зависимости будут инъектированы, используют аннотацию @PostConstruct:
@Service public class MyService { private Dependency dependency;@Autowired public void setDependency(Dpendency dependency) { this.dependency = dependency; }
@PostConstruct public void init() { this.dependency.doSomething(); } }