Spring Framework :: Связи между объектамиТрадиционный подходPersonCompanyclass Person { public String name; public Company company; public Person() { name = “Иван Иванов”; Company company = new Company(); company.name = “Luxoft”; }}class Company { public String name;}
Слайд 2
Spring Framework :: Связи между объектами Традиционный подход Person Company class Person
{ public String name; public Company company;
public Person() { name = “Иван
Иванов”; Company company = new Company(); company.name = “Luxoft”; } }
class Company { public String name; }
Слайд 3
Проблемы: Класс А напрямую зависит от класса В; Невозможно тестировать
А в отрыве от В (если для В нужна
база – для тестирования А она также понадобится); Временем жизни объекта В управляет А – нельзя использовать тот же объект в других местах; Нельзя «подменить» В на другую реализацию;
A
B
Традиционный подход
Spring Framework :: Связи между объектами
Слайд 4
Подход с использованием паттерна Singleton IvanovPerson LuxoftCompany class IvanovPerson extends Person
{ public Person ivanovPerson = new Person(); public static Person create()
{ ivanovPerson.name = “Иван Иванов”; ivanovPerson.company = LuxoftCompany.create(); return ivanovPerson; } } class LuxoftCompany extends Company { public Company luxoftCompany = new Company(); public LuxoftCompany() { luxoftCompany = “Luxoft”; } public static Company create() { return luxoftCompany; } }
class Person { public String name; public Company company; }
class Company { public String name; }
Spring Framework :: Связи между объектами
Слайд 5
Подход с использованием паттерна Singleton IvanovPerson LuxoftCompany Отдельный класс специально под
нашу задачу В коде IvanovPerson.create() стоит прямая ссылка на этот
класс В случае перевода Иванова в другую компанию, надо менять этот код Для тестирования невозможно «на время» подменить компанию
Spring Framework :: Связи между объектами
Слайд 6
Person Company Подход с использованием IoC
id=“luxoftCompany" class=“Company">
ref=“companyReport"/>
POJO – plain old Java Object
application-context.xml
class Person { public String name; public Company company; }
class Company { public String name; }
class BankApplication { @Autowired @Required private CR companyReport; public void setCompanyReport() ;
Spring Framework :: Связи между объектами
Слайд 7
Person Company Подход с использованием IoC Преимущества: контейнер создает необходимые объекты и
управляет их временем жизни
Person и Company не связаны друг
с другом и независимы от внешних библиотек
application-context документирует систему и связи между объектами
легкость внесения изменений в связи системы
Spring Framework :: Связи между объектами
Слайд 8
Spring Framework :: Связи между объектами A B A B Репозиторий JNDI Имя B_NAME для
поиска B Регистрация в JNDI под именем B_NAME Традиционный подход: связи
между объектами внутри кода
Паттерн Service Locator (JNDI в JEE): объекты в репозитории
IoC: объекты ничего не знают друг о друге
A
B
Application context
- cоздает объект A - инициализирует
- cоздает объект A - инициализирует, сообщая о B
class A { private B b; }
class B { }
Слайд 9
Инверсия управления (Inversion of Control, IoC) — принцип
объектно-ориентированного программирования, используемый для уменьшения связанности объектов. Модули верхнего уровня
не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Spring Framework :: IoC
Техники реализации:
Фабричный метод (англ. Factory pattern) Service locator (англ. Service locator pattern) Внедрение зависимости (англ. Dependency injection) Через метод класса (англ. Setter injection) Через конструктор (англ. Constructor injection) Через интерфейс внедрения (англ. Interface injection) IoC контейнер (англ. IoC-container)
Слайд 10
Spring Framework :: IoC / DI Преимущества IoC контейнеров: Управление
зависимостями и применение изменений без перекомпиляции; Упрощение повторного использования классов
или компонентов; Упрощение unit-тестирования; Более "чистый" код (классы не инициализируют вспомогательные объекты); В IoC контейнер лучше всего выносить те интерфейсы, реализация которых может быть изменена в текущем проекте или в будущих проектах.
Слайд 11
Spring Framework :: Семейство IoC контейнеров BeanFactory – базовый
интерфейс, представляющий IoC контейнер в Spring Framework (используемая реализация:
XmlBeanFactory): BeanFactory предоставляет только базовую низкоуровневую функциональность. ApplicationContext – интерфейс, расширяющий BeanFactory и добавляющий различную функциональность к базовым возможностям контейнера: простота интеграции со Spring AOP; работа с ресурсами и сообщениями; обработка событий; поддержка интернационализации; Специфические контексты приложений (как, например, WebApplicationContext);
Слайд 12
Spring Framework :: Семейство IoC контейнеров Существует несколько реализаций
ApplicationContext, доступных для использования. Основными являются: GenericXmlApplicationContext (since v.3.0); ClassPathXmlApplicationContext; FileSystemXmlApplicationContext; WebApplicationContext; XML является
традиционным способом задания конфигурации контейнера, хотя существуют и другие способы задания метаданных (аннотации, Java код и т.д.); Во многих случаях проще и быстрее конфигурировать контейнер с помощью аннотаций. Но надо помнить, что аннотированные конфигурации содержат некоторые ограничения и вносят дополнительные зависимости на уровене кода; В большинстве случаев пользователю (разработчику) не придется самому инициализировать Spring IoC контейнер;
Слайд 13
Spring Framework :: Работа с IoC контейнером В общем
виде, работа IoC контейнера Spring может быть представлена в
виде следующей диаграммы:
В процессе создания и инициализации контейнера классы вашего приложения объединяются с метаданными (конфигурацией контейнера) и на выходе вы получаете полностью сконфигурированное и готовое к работе приложение.
Слайд 14
Spring Framework :: Работа с IoC контейнером Создание контейнера: public
void main() { ApplicationContext context = new ClassPathXmlApplicationContext(”application-context.xml");
такой инструкции бин с именем originalName будет также доступен
под именем aliasName;
Такая необходимость часто возникает, когда архитектура приложения изначально создана с учетом возможности расширения, но при этом пока в конкретных разделах такой необходимости не возникает (и, соответственно, нет смысла плодить дополнительные объекты).
Слайд 22
Spring Framework :: DI Внедрение зависимости через конструктор public class
Слайд 25
Spring Framework :: Autowiring Пример: сервисный класс для получения
информации о пользователях UserDirectory LDAPUserDirectory DatabaseUserDirectory MockUserDirectory
class LoginManager { UserDirectory userDirectory; }
class UserDirectorySearch {
UserDirectory userDirectory; }
class UserInfo { UserDirectory userDirectory; }
Пусть есть классы, которым нужна информация о пользователях:
class=“UserDirectorySearch”>
Слайд 26
Spring Framework :: Autowiring Теперь включим автоматическое связывание (autowire)
id=“userDirectory” class=“LDAPUserDirectory” />
id=“userInfo“ class=“UserInfo“ autowire="byType“>
class LoginManager { UserDirectory userDirectory; }
class UserDirectorySearch { UserDirectory userDirectory; }
class UserInfo { LDAPUserDirectory ldapUserDirectory; }
Свойство userDirectory автоматически инициализируется:
Слайд 27
Spring Framework :: Autowiring Spring может автоматически связывать (добавлять
зависимости) между бинами вместо ;
В некоторых случаях это может
существенно сократить объем затрат на конфигурирование контейнера; Позволяет автоматически обрабатывать изменения в связи с расширением объектной модели (например, при добавлении новых зависимостей они подключатся автоматически); Связывание по типу может работать, когда доступен только один бин определенного типа; Менее понятно для чтения и прослеживания зависимостей, чем явное задание зависимостей (магия!);
Задается с помощью атрибута autowire в определении бина
Слайд 28
Spring Framework :: Autowiring Типы автоматического связывания: no – запрет
на автосвязывание – значение по умолчанию; byName – автосвязывание по
имени свойства. Контейнер будет искать бин с ID, совпадающим с именем свойства. Если такой бин не найден – объект остается несвязанным; byType – автосвязывание по типу параметра. Работает только в случае наличия единственного экземпляра бина соответствующего класса в контейнере. Если более одного бина – UnsatisfiedDependencyException; constructor – контейнер ищет бин (или бины) совпадающие по типу с параметрами конструктора. Если более одного бина одного типа или более одного конструктора – UnsatisfiedDependencyException;
Слайд 29
Spring Framework :: Использование аннотаций Контейнер Spring также может
быть сконфигурирован с использованием аннотаций;
Основные типы поддерживаемых аннотаций: @Required @Autowired @Component
Для поддержки
конфигурации через аннотации, в конфигурации Spring контейнера должно быть указано следующее свойство:
Слайд 30
Spring Framework :: Использование аннотаций @Required Применяется только к SET
методам бинов; Определяет что соответствующее свойство бина должно быть вычислено
на этапе конфигурации (через конфигурацию или автоматическое связывание); Если соответствующее свойство не может быть задано – контейнер сгенерирует соответствующее исключение, что позволит избежать «неожиданных» NullPointerException в процессе работы системы;
public class SimpleMovieLister { private MovieFinder movieFinder;
Слайд 33
Spring Framework :: Использование аннотаций @Component
Используется для задания Spring
компонент без использования XML конфигурации Применяемся к классам Является базовым стереотипом
для любого Spring-managed компонента Рекомендуется использовать более точные стереотипы: @Service @Repository @Controller В большинстве случаев, если вы не уверены, какой именно стереотип использовать – используйте @Service Для автоматической регистрации бинов через аннотации необходимо указать следующую инструкцию в конфигурации контейнера:
class CustomEvent extends ApplicationEvent { public CustomEvent (Object obj) { super(obj); } } context.publishEvent(new CustomEvent(new Object()));
Слайд 42
Spring Framework :: События Обработка событий внутри ApplicationContext обеспечивается
при помощи Класса ApplicationEvent Интерфейса ApplicationListener
При наступлении события нотифицируются все бины,
зарегистрированные в контейнере и реализующие интерфейс ApplicationListener
ApplicationEvent – основные реализации: ContextRefreshedEvents – создание или обновление ApplicationContext Синглетоны созданы ApplicationContext готов к использованию ContextClosedEvent после использования close() метода RequestHandledEvent только для веб приложения
Слайд 43
Spring Framework :: События Пример: регистрация нового сотрудника в
компании.
Возможные получатели события: - оповещение охранников, чтобы сделали пропуск - охранники
подписываются на событие - дополнительно могут подписаться бухгалтерия, отдел кадров - допустим надо добавить новую функциональность: регистрировать новых сотрудников в базе данных - для этого нам достаточно создать класс для регистрации и подписаться на событие добавления сотрудника
Преимущества: Получателей может быть как угодно много; Добавление получателя не добавляет зависимости: о получателе знает только он сам
Недостатки: - Приводит к неявному поведению приложения
и, соответственно, предоставляет функциональность интернационализации (i18n)
При загрузке автоматически ищет
MessageSource бин в конфигурации (бин должен наследоваться от MessageSource и иметь id=“messageSource”)
Если такой бин не может быть найден нигде в контексте – ApplicationContext создает экземпляр «заглушки» - DelegatingMessageSource для корректной обработки соответствующих методов
Слайд 45
Spring Framework :: Локализация messages_en_US.properties
new GenericXmlApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); ctx.load("classpath:/com/bank/config/xml/*-config.xml"); ctx.refresh();
Указание профиля и загрузка конфигурации в Java-коде:
-Dspring.profiles.active="profile1,profile2"
Указание профиля в параметрах командной строки:
Слайд 58
Spring Framework :: Java-based конфигурация @Configuration @Profile(“dev”) public class TransferServiceConfig { @Autowired
DataSource dataSource; @Bean public TransferService transferService() { return new DefaultTransferService(accountRepository(), feePolicy()); } @Bean public AccountRepository
accountRepository() { return new JdbcAccountRepository(dataSource); } @Bean public FeePolicy feePolicy() { return new ZeroFeePolicy(); } }
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); // find and register all @Configuration classes within ctx.scan("com.bank.config.code"); ctx.refresh();
Слайд 59
Упражнения №4: Разработка простейшего приложения: 50 мин – самостоятельная работа; 10