Содержание

Интерфейс ApplicationContext

Интерфейс org.springframework.context.ApplicationContext описывает основной функционал управляющего компонентами приложения контейнера Спринг. Именно имплементации этого класса создают, настраивают и внедряют друг в друга компоненты приложения, так называемые бины (Spring bean).

Параметры создания бинов и граф их зависимостей представляет собой так называемые конфигурационные метаданные (configuration metadata), ну, или просто конфигурацию приложения. Эта конфигурация должны описать какой компонент (бин) с какими параметрами создаётся, какие компоненты в какие внедряются в качестве зависимостей. Следуя описанной конфигурации контейнер во время старта приложения создаст все эти компоненты и свяжет их друг с другом, предоставив нам полностью готовое и сконфигурированное приложение.

Способы конфигурации Spring приложения

Существует несколько довольно разных способов передать Спрингу конфигурационные метаданные, то есть сообщить ему, какие бины нужно создать, как их инициализировать и как их внедрить друг в друга.

Например, нам нужно сообщить всем компонентам приложения, которые взаимодействуют с базой данных, по какому URL'у эта БД вообще доступна. Значит нам надо передать (пролить) строку вроде

jdbc:postgresql://localhost/test?user=fred&password=secret&ssl=true

в приложение. Эта строка – это и есть простейший параметр конфигурации приложения. И передать приложению этот параметр мы сможем одним из следующих способов:

Спринг позволяет использовать одновременно несколько различных способов описания конфигурации. Все настройки будут вычитаны и применены к приложению, как если бы они были описаны единообразно.

Конфигурация в виде Java кода

Самым распространённым на сегодняшний день способом передать Спрингу сведения о том, как нужно сконфигурировать компонент – это использование непосредственно java кода. Здесь сеть два подхода:

Первый называется Конфигурацией с помощью аннотаций (Annotation-based configuration) и заключается в том, что классы, объекты которых должны быть сконфигурированы как программные компоненты, управляемые контейнером, помечаются специальными аннотациями. При старте приложения Спринг вычитывает эти аннотации и в соответствии с ними как-то поступает с данным классом, например, инициализирует его объект и внедряет в качестве зависимости в другие объекты.

@Component
public class DatabaseInitiaizer {
 
    private List < User > listOfUsers = new ArrayList < > ();
 
    @PostConstruct
    public void init() {
        User user = new User(1, "User");
......

Второй называется Конфигурацией с помощью джавы (Java-based configuration) и заключается в том, что пишутся специальные конфигурационные классы, методы которых возвращают должным образом сконфигурированные бины. При таком подходе разработчик сам внутри этого метода создаёт объекты-экземпляры программных компонентов с помощью new либо фабричных методов. Однако и здесь Спринг даёт возможность легко получить доступ к любым необходимым зависимостям без необходимости инстанциировать эти зависимости вручную.

@Configuration
public class Config {
 
    @Bean
    public Connection mySQLConnection() {
        return new MySQLConnection();
    }
 
    @Bean
    public Connection oracleConnection() {
        return new OracleConnection();
    }
}

Поскольку первый подход (обложить класс надлежащими аннотациями) предполагает доступ разработчика к исходному коду компонента, то он, как правило, чаще всего применяется к компонентам, разрабатываемым авторами данного приложения. Второй подход не требует доступа к исходникам и позволяет сделать бином абсолютно любой библиотечный компонент (хоть произвольную строку, что-угодно, что может быть объектом).

Так, если нам нужен в качестве бина, внедряемого в наши компоненты, например, http-клиент, на не нужно писать свой клиент или оборачивать библиотечный. Мы можем объявить объект класса java.net.http.HttpClient бином с помощью второго подхода Спринг внедрит его во все компоненты, где он требуется.

Обратим внимание, что конфигурация с помощью джавы не обязательно должна лежать в одном классе, в одном файле. Обычно какие-то однотипные бины конфигурируют в одном классе, какие-то другие в других классах.

Конфигурация с помощью XML

Перечислить классы, которые должны быть бинами и управляться контейнером, можно в специальном xml-файле примерно следующего вида:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">
 
	<!-- services -->
 
	<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
		<property name="accountDao" ref="accountDao"/>
		<property name="itemDao" ref="itemDao"/>
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>
 
	<!-- more bean definitions for services go here -->
 
</beans>

Описания бинов, их взаимозависимости располагаются в одном или нескольких xml- файлов. Есть различные способы указать Спрингу из каких файлов вычитывать конфигурации и он будет их обрабатывать, как если бы они были в одном файле.

Конфигурация с помощью groovy файлов

Конфигурация приложения и его компонентов может быть описана в groovy файлах. Groovy, будучи функциональным языком программирования, очень хорошо подходит для написания кода в декларативном стиле, что в свою очередь делает его очень удобным для описания различных конфигураций. Однако, по каким-то причинам такой подход к описанию конфигурации Spring Приложений не прижился.

Выглядит конфигурация, описанная с помощью groovy следующим образом:

beans {
	dataSource(BasicDataSource) {
		driverClassName = "org.hsqldb.jdbcDriver"
		url = "jdbc:hsqldb:mem:grailsDB"
		username = "sa"
		password = ""
		settings = [mynew:"setting"]
	}
	sessionFactory(SessionFactory) {
		dataSource = dataSource
	}
	myService(MyService) {
		nestedBean = { AnotherBean bean ->
			dataSource = dataSource
		}
	}
}