Spring Context
Под словом «Spring» обычно подразумевают просто IoC-контейнер, помогающий структурировать Java-приложения. В действительности под словом «Spring» скрывается целый мир.
IoC-контейнер, это замечательный способ собрать приложение «по кусочкам» из разных компонентов. Spring же предоставляет удобные способы как написания данных «кусочков», так и объединения их в единое приложение. Например, у нас есть два класса.
Сервис:
class MyService { private ServiceDependency dependency; public MyService(ServiceDependency dependency) { this.dependency = dependency; } public void usefulWork() { this.dependency.dependentWork(); } }
И его зависимость:
class ServiceDependency { // fields public ServiceDependency() { } public void dependentWork() { // any actions } }
Данные, компоненты уже достаточно неплохо. Наличие же интерфейсов мы для простоты опустим. Самый простой способ объединить эти компоненты в единое приложение – это написать что-то вроде:
public class MainClass { public static void main(String[] args) { ServiceDependency dep = new ServiceDependency(); MyService service = new MyService(dep); service.usefulWork(); } }
Несмотря на простоту, данный код обладает серьёзными недостатками, которые являются критическими для больших проектов. Действительно, в данном примере вполне очевидно, что экземпляр класса ServiceDependency необходимо создавать раньше, чем экземпляр объекта MyService. А в больших проектах таких сервисов и зависимостей может быть столько, что перебор программистом порядка создания объектов занимал бы совсем неприличное время.
Хочется автоматического разрешения зависимостей, и чтобы даже не задумываться о создании объектов. Здесь и приходит на помощь Spring, а если быть точнее, то Spring Context. Модифицируем немного наши классы, добавив так называемые аннотации стереотипов.
import org.springframework.stereotype.Service; @Service class MyService { @Service class ServiceDependency { Ну и, конечно, MainClass: @Configuration @ComponentScan public class MainClass { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(MainClass.class); MyService service = ctx.getBean(MyService.class) service.usefulWork(); } }
И всё! Обратите внимание, что здесь не написано ни одно new наших сервисов.
Разберём подробнее
MainClass помечен аннотацией @Сonfiguration, говорящей о том, что в данном классе содержится конфигурация так называемого контекста Spring.
Как ни странно, из конфигурации в данном классе только аннотация @ComponentScan, которая говорит Spring искать все классы, помеченные Spring-аннотациями (в частности аннотациями стереотипов @Service).
Каждый класс помечен аннотацией @Service. Данные аннотация говорит Spring создать экземпляр объекта данного класса и положить его в некоторое множество таких объектов. Такие объекты, собственно, и называются beans, а множество таких объектов, соответственно, называется контекстом.
Ну и в методе main создаётся тот самый контекст: Spring автоматически определит зависимости beans друг с другом (начиная со Spring 4.0 наличие аннотации @Autowired не обязательно, если есть ровно один конструктор) и создаст экземпляры объектов в нужном порядке. Остаётся только получить экземпляр этого объекта и вызвать метод.
Данный пример, разумеется, рассматривает только один из вариантов создания beans в Spring Context. В действительности, возможностей Spring Context гораздо больше.
Есть вопрос? Напишите в комментариях!