Inversion of Control(Ioc), Dependecy Injection(DI), Spring Container.
Перед определением IoC и DI, стоит кратко рассмотреть, что такое Spring Container. Данный контейнер является ответственным за создание и управление объектов (это контейнер, в котором будут находиться созданные объекты(бины), откуда мы их сможем извлекать, запустив приложение). Контейнер будет читать наш configuration file и внутри контейнера будет создаваться бин, который мы опишем в конфигурационном файле.
Основные ф-ии, которые выполняет Spring Container:
-IoC - инверсия управления. Создание и управление объектами (аутсорсинг создания и управления объектами. Т.е. передача программистом прав на создание и управление объектами Spring-y.).
-DI (Dependency Injection) - внедрение зависимостей (стоит вспомнить, что в сложной программе, множество объектов зависят друг от друга). (Аутсорсинг добавления/внедрения зависимостей. DI делает объекты нашего приложения слабо зависимым друг от друга).
Способы конфигурации Spring Container (способ дать понимание того, какие объекты нужно создавать, с помощью IoC):
-XML file(устаревший способ);
При создании файла, по стандарту, он имеет название applicationContext.xml. Внутри файла, помимо стандартной настройки, мы создаем необходимый для нас объект(бин):
<bean id = "myPet" //идентификатор бина
class = "spring_introduction.Dog"> //полное имя класса
<\bean>
Таким образом, при запуске нашего приложения, будет создаваться объект Dog и помещаться в Spring Container. Далее, с помощью id мы сможем получить объект из контейнера.
Для получения бина из SpringContainer нам нужно создать Application Context, в аргумент мы можем передать несколько файлов xml, если это необходимо (context всегда нужно закрывать!).
ClassPathXmlApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml");
Pet pet = context.getBean("myPet", Pet.class); //обращаемся к объекту
pet.say(); //вызываем его метод
context.close; //закрываем контекст
-Annotations + XML file (современный способ);
Аннотации – это специальные комментарии/метки/метаданные, которые нужны для передачи определенной информации.
Конфигурация с помощью аннотаций более короткий и быстрый способ, чем конфигурация с помощью XML файла.
Порядок действий состоит из двух этапов:
-происходит сканирование классов и поиск аннотации @Component;
-далее, создание(регистрация) бина в Spring Container.
В конфиг файле необходимо обозначить пакет, в котором будет проходить сканирование на наличие component (также, скан пройдет и в подпакетах):
<context:component-scan base-package="spring_introduction"/>
Далее, классы, которые имеют аннотацию @Component, будут добавлены в контейнер и ими можно будет пользоваться, через создание Application Context.
При добавлении аннотации @Component(“”), -> в скобках указывается id бина. Если к аннотации @Component не прописать bean id, то бину будет назначен дефолтный id (дефолтный id получается из имени класса, заменяя его первую заглавную букву на прописную). (хорошим тоном считается прописать свой id).
-Java code(современный способ);
Использование java code в качестве конфигурации Spring Container, обладает двумя способами:
1 способ заключается в создании класса MyConfig (название класса может быть любым):
@Configuration
@ComponentScan("spring_introduction")
public class MyConfig {}
@Configuration – означает, что данный класс является конфигурацией.
С помощью аннотации @ComponentScan мы показываем, какой пакет нужно сканировать на наличие бинов и разных аннотаций.
В таком случае, настроить Application Context уже необходимо с помощью другого класса:
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(MyConfig.class);
Остальные классы, которые мы определяем в бины, имеют всё те же аннотации по определению в контейнер и по внедрению зависимости.
2 способ не использует сканирование пакета и поиск бинов(сокращает кол-во аннотаций в коде).
@Configuration
public class MyConfig {}
В следствие этого, мы не нуждаемся в определении бинов с помощью @Component и в определении зависимости с помощью @Autowired.
В классе MyConfig, прописываем методы, которые добавляют наши бины, с помощью аннотации @Bean(аннотация перехватывает все обращения к бину и регулирует его создание):
@Bean
public Pet catBean(){return new Cat();}
Также, мы можем добавить аннотацию @Scope, для определения состояния бина, выбрав один из двух вариантов, и указав его в скобках (singletone или prototype).
Далее, для внедрения зависимости, мы создаем следующий метод, в том же классе MyConfig:
@Bean
public Person personBean(){return new Person(catBean());}
Следующий шаг, установим значения для нашего объекта типа Person, и как было описано выше, воспользуемся нашим properties файлом. Но теперь мы пропишем конфигурацию не в XML файле, а в классе MyConfig с помощью аннотации @PropertySource.
Для этого мы добавляем аннотацию к описанию класса и в скобках указываем путь до нашего файла:
@Configuration
@PropertySource("classpath:myApp.properties")
public class MyConfig {…}
Способы внедрения зависимостей (DI):
-С помощью конструктора;
<bean id = "myPerson" //идентификатор бина
class = "spring_introduction.Person"> //полное имя класса
<constructor-arg ref="myPet"/> //конструктор класса, с указанием аргумента
</bean>
В примере выше, бин myPerson зависит от бина myPet.
Далее в приложении:
Person person =
context.getBean("myPerson", Person.class); //объявляем бин
person.callYourPet(); //вызываем необходимый метод
context.close() //закрываем контекст
-С помощью сеттеров;
<bean id = "myPerson"
class = "spring_introduction.Person">
<property name="pet" ref="myPet"/> //pet это конвертация от setPet
</bean>
-Autowiring;
…рассмотрим позже.
Внедрение строк и других значений из properties файла:
Создаем файл myApp.properties, в нем установим конкретные значения:
person.surname = Khakimov
person.age = 27
Далее, для его чтения, перед созданием бинов, мы прописываем следующую конфигурацию:
<context:property-placeholder
location="classpath:myApp.properties"/>
И в бине прописываем следующие значения:
<bean id = "myPerson"
class = "spring_introduction.Person">
<property name="pet" ref="myPet"/>
<property name="surname" value="${person.surname}"/> <property name="age" value="${person.age}"/>
</bean>
Что такое бины? Sping Bean – это объект, который создается и управляется Spring Container. Например, когда мы сами создаем new объект, то и называем его объектом. В случае, когда объект создает Spring Container, он называется - бин(bean).
Что такое Bean Scope? Scope(область видимости) определяет:
-жизненный цикл бина;
-возможное кол-во создаваемых бинов;
Разновидности bean scope { singletone, prototype, request, session, global-session} singltone
– дефолтный scope (можно создать только один объект)
-такой бин создается сразу после прочтения Spring Container конфиг файла; -является общим для всех, кто запросит у Spring Container;
-подходит для stateless объектов (объекты, которые менять не придется); prototype
-такой бин создается только после обращения к Spring Container с помощью метода getBean;
-для каждого такого обращения создается новый бин в Spring Container; -подходит для stateful объектов (объекты, которые хранят какое то состояние);