Inversion of control & Dependency Injection
Інверсія управління (англ. Inversion of Control, IoC) – абстрактний принцип, набір рекомендацій для написання слабо зв'язаного коду. Компонент системи має бути максимально ізольованим від інших компонентів, не покладаючись на деталі їхньої реалізації.
Впровадження залежностей (англ. Dependency Injection, DI) – процес надання зовнішньої залежності компоненту. Одна із реалізацій IoC.
IoC «Hollywood Principle»
IoC-контейнер
Контейнер Spring IoC представлений інтерфейсом org.springframework.context.ApplicationContex.
Контейнер створює, налаштовує та збирає компоненти вашого застосунку.
Інформацію про те, як це реалізовувати, контейнер отримує з конфігурації.
Тип конфігурації вибираєте ви.
• XML based
• Annotation based
• Java based
AnnotationConfigApplicationContext
AnnotationConfigWebApplicationContext
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
GenericApplicationContext
GenericGroovyApplicationContext
GenericWebApplicationContext
GenericXmlApplicationContext
GroovyWebApplicationContext
ResourceAdapterApplicationContext
StaticApplicationContext
StaticWebApplicationContext
XmlWebApplicationContext
Використання контейнеру
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
Отримання інстансу контексту:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
Використання контейнеру
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
Використання контейнеру
Отримання біну з контексту застосунку:
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class);
List userList = service.getUsernameList();
Атрибути біну
name class scope
parent abstract lazy-init
autowire depends-on alias
init-method destroy-method factory-method
factory-bean
Атрибути біну
Розглянемо атрибут factory-method:
Якщо ваш клас спроєктовано так
public class Service {
private static Service service = new Service();
private Service() {}
public static Service createInstance() { return service; }
}
У вас немає паблік конструктора для інстаціювання об'єкта класу, але є фабричний метод, який
повертає інстанс класу, то можна використовувати таку конструкцію:
<bean id="service" class="my.package.Service" factory-method="createInstance"/>
Розглянемо атрибут factory-bean:
Якщо ваш клас спроєктовано так
public class ServiceManager {
private static MathService mathService = new
MathServicempl();
private static BiologyService biologyService = new
BiologyServiceImpl();
private ServiceManager() {}
public MathService createMathServiceInstance() {
return mathService; }
public BiologyService createBiologyServicenstance() {
return biologyService; }
}
<bean id="serviceManager"
class="my.package.ServiceManager">
</bean>
<bean id="biologyService"
factory-bean="serviceManager"
factory-method="createBiologyServicenstance"/>
<bean id="mathService"
factory-bean="serviceManager"
factory-method="createMathServiceInstance"/>
Найменування бінів
Необхідно для того, щоб ви могли отримувати біни з контейнера за вказаним ідентифікатором.
Для цього під час оголошення біну використовується атрибут id, name. Ідентифікатор може бути лише один, а імен може бути кілька, вони вказуються через кому («bean,mybean,myBean»), крапку з комою («bean;mybean;myBean») або через пробіл («bean mybean myBean»).
Оголошення біну з внутрішнім біном без імені:
<bean id="CustomerBean" class="my.package.Customer”>
</bean>
<constructor-arg>
<bean class="my.package.Person">
<property name="name" value="Peter" />
</bean>
</constructor-arg>
Якщо необхідно дати якийсь аліас (псевдонім) біну поза його оголошенням, можна використовувати таку конструкцію:
<alias name="fromName" alias="toName"/>
Впровадження залежностей
Впровадження залежностей:
• поле;
• конструктор;
• setter-метод.
Впровадження через конструктор виглядає так:
package my.package;
public class X {
public X(Y y, Z z) {
// ...
}
}
<beans>
<bean id="foo" class="my.package.X">
<constructor-arg ref="y"/>
<constructor-arg ref="z"/>
</bean>
<bean id="y" class="my.package.Y"/>
<bean id="z" class="my.package.Z"/>
Явне зазначення типів також допускається для зручності розробників.
package my.package;
public class Item {
int sum;
String description;
public Item(int sum, String desc) {
// ...
}
}
<beans>
<bean id="item" class="my.package.item">
<constructor-arg type="java.lang.String” value="Bentley car"/>
<constructor-arg type="int" value="900000"/>
</bean>
</beans>
Також можна вказати індекс:
package my.package;
public class Item {
int sum;
String description;
public Item(int sum, String desc) {
// ...
}
}
<beans>
<bean id="item" class="my.package.item">
<constructor-arg index="1" value="Bentley car"/>
<constructor-arg index="0" value="900000"/>
</bean>
</beans>
Навіть можна вказати ім'я:
package my.package;
public class Item {
int sum;
String description;
public Item(int sum, String desc) {
// ...
}
}
<beans>
<bean id="item" class="my.package.item">
<constructor-arg name="desc" value="Bentley car"/>
<constructor-arg name="sum" value="900000"/>
</bean>
</beans>
Впровадження через setter-метод відбувається так:
package my.package;
public class Z {
private X x;
private Y y;
private int value;
public void setX(X x) {
this.x = x;
}
public void setY(Y y) {
this.y = y;
}
public void setValue(int value) {
this.value = value;
}
}
<bean id="z" class="my.package.Z">
<property name="x">
<ref bean="x"/>
</property>
<property name="y" ref="y"/>
<property name="value" value="1"/>
</bean>
<bean id="x" class="my.package.X"/>
<bean id="y" class="my.package.Y"/>
Lazy init
За замовчуванням встановлена рання ініціалізація бінів, але цю поведінку можна змінити:
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
Також це можна контролювати на рівні контейнера загалом:
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
Етапи створення біну
Перед тим як ви отримаєте свій бін, він пройде такі етапи:
Анотації для задання атрибутів біну:
<context:annotation-config/> – у конфігурації XML потрібно обов'язково вказати цю директиву.
@Required
@Autowired
@PostConstruct, @PreDestroy
@Qualifier
@Scope
@Component
@Lazy
Q&A
Дякую всім за заняття!🙌🏻
❗️🎓2. Впровадження залежностей та IoC контейнер
Нагадую, що дедлайн здачі домашніх робіт – до наступного уроку.
Якщо виникають складнощі, пишіть, допоможу із задоволенням 😌
Запис лекції тренер опублікує трохи пізніше 🖥
Не забудьте повторити матеріал та підготуватися до наступного уроку📚
Успіху і до зустрічі!🤩
PRO. 1
Прізвище
Ім'я
По батькові
Стать
Посада
Дата народження
Вивести дані про інженерів, пенсійного віку (чоловікам більше 65-ти років, жінкам 60).
PRO. 2
No поїзда
Пункт і час прибуття
Пункт і час відбуття
Вивести всі відомості про поїзди, час перебування в дорозі яких перевищує 7 годин 20 хвилин.
Обчислити середню вартість усіх комп'ютерів і надрукувати найменування комп'ютерів та їхню середню вартість.
PRO. 3
Прізвище
Ім'я
По батькові
Посада
Зарплата
Дата народження
Вивести відомості про працівників, у яких зарплата вища за середню і вік менше 30-ти років.