Evgeniy Krivosheev Andrey Stukalenko Vyacheslav Yakovenko Vladimir Sonkin Last update: Feb, 2013 Spring Framework Module 2 – Components Model (IoC, DI)

Презентация:



Advertisements
Похожие презентации
Evgeniy Krivosheev Vyacheslav Yakovenko Last update: Feb, 2012 Spring Framework Module 4 – JNDI.
Advertisements

Обзор возможностей Инверсия управления Аспектно-ориентированное программирование.
Методики «Inversion of Control» и «Dependency Injection». Применение в Spring. Малышкин Фёдор
Evgeniy Krivosheev Last update: March, 2012 Spring Framework Module 10 – JMS, EJB.
Обзор возможностей Инверсия управления Аспектно-ориентированное программирование.
Обзор возможностей Инверсия управления Аспектно-ориентированное программирование.
1 Java 6. ИНТЕРФЕЙСЫ И ВНУТРЕННИЕ КЛАССЫ. 2 Интерфейсы Не являются классами Ни один из объявленных методов не может быть реализован внутри интерфейса.
Ресурсы WPF Два типа ресурсов WPF: объектные ресурсы (object resource) – определенный.NET-объект, который можно использовать многократно; ресурсы сборки.
©Павловская Т.А. (СПбГУ ИТМО) Курс «С#. Программирование на языке высокого уровня» Павловская Т.А.
1 © Luxoft Training 2012 Java: расширенные вопросы Модуль #8.
Основы ООП и C# Работа с объектами и классами. Классы Класс специальный тип данных для описания объектов. Он определяет данные и поведение типа. Определение.
1 Классы в Java Ключевое слово class означает: Я говорю тебе, как выглядит новый тип объекта. Класс является базовым элементом объектно-ориентированного.
Наследование Наследование – это отношение является между классами. class Person { string first_name; int birth_year;... } class Student : Person { float.
Полиморфизм. Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Проф. В.К.Толстых, Технологии разработки Internet- приложений ASP.NET приложения – Модули HTTP, фильтры, события приложения - Global.asax.
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
1 © Luxoft Training 2012 Spring Framework Inversion of control Part 1.
Классы в C#. Две роли классов Класс Класс – это модуль, архитектурная единица построения программной системы. Модульность построения – основное свойство.
Дружественные функции Дружественные функции – это функции, объявленные вне класса, но имеющие доступ к закрытым и защищенным полям данного класса Дружественная.
Evgeniy Krivosheev Vyacheslav Yakovenko Last update: Feb, 2012 Spring Framework Module 4 – DAO, JDBC.
Транксрипт:

Evgeniy Krivosheev Andrey Stukalenko Vyacheslav Yakovenko Vladimir Sonkin Last update: Feb, 2013 Spring Framework Module 2 – Components Model (IoC, DI)

2 Spring Framework :: Связи между объектами Традиционный подход PersonCompany class Person { public String name; public Company company; public Person() { name = Иван Иванов; Company company = new Company(); company.name = Luxoft; } class Company { public String name; }

3 Проблемы: o Класс А напрямую зависит от класса В; o Невозможно тестировать А в отрыве от В (если для В нужна база – для тестирования А она также понадобится); o Временем жизни объекта В управляет А – нельзя использовать тот же объект в других местах; o Нельзя «подменить» В на другую реализацию; AB Традиционный подход Spring Framework :: Связи между объектами

4 Подход с использованием паттерна Singleton IvanovPersonLuxoftCompany 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 IvanovPersonLuxoftCompany -Отдельный класс специально под нашу задачу -В коде IvanovPerson.create() стоит прямая ссылка на этот класс -В случае перевода Иванова в другую компанию, надо менять этот код -Для тестирования невозможно «на время» подменить компанию Spring Framework :: Связи между объектами

6 PersonCompany Подход с использованием IoC <property name=companyReport" ref=companyReport"/> POJO – plain old Java Objectapplication-context.xml class Person { public String name; public Company company; } class Company { public String name; } class private CR companyReport; public void setCompanyReport() ; Spring Framework :: Связи между объектами

7 PersonCompany Подход с использованием IoC Преимущества: -контейнер создает необходимые объекты и управляет их временем жизни -Person и Company не связаны друг с другом и независимы от внешних библиотек -application-context документирует систему и связи между объектами -легкость внесения изменений в связи системы Spring Framework :: Связи между объектами

8 AB AB Репозиторий JNDI Имя B_NAME для поиска B Регистрация в JNDI под именем B_NAME Традиционный подход: связи между объектами внутри кода Паттерн Service Locator (JNDI в JEE): объекты в репозитории IoC: объекты ничего не знают друг о друге AB Application context - создает объект A - инициализирует - создает объект 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"); BankApplication bankApplication = context.getBean(bankApplication); } ApplicationContext context = new ClassPathXmlApplicationContext( new String[] {"services.xml", "daos.xml"});

15 Spring Framework :: Работа с IoC контейнером Пример конфигурации: <beans xmlns=" xmlns:xsi=" xsi:schemaLocation="

16 Spring Framework :: Создание Bean При помощи конструктора: <bean id=example1" class="ru.luxoft.training.samples.Example" /> При помощи статического фабричного метода: <bean id="clientService" class="ru.luxoft.training.samples.ClientService" factory-method="createInstance" /> При помощи не статического фабричного метода : <bean id="serviceFactory" class="examples.DefaultServiceFactory" /> <bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance" />

17 Spring Framework :: Отложенная инициализация Для конкретного бина : <bean id=lazy" class=ru.luxoft.training.ClientService" lazy-init=true" /> Для всех бинов в контейнере: … Если singleton - бин зависит от lazy - бина, то lazy - бин создастся сразу, при создании singleton - бина.

18 Упражнения 3: Hello, World пример для Spring Framework: –20 мин – самостоятельная работа; –10 мин – обсуждение;

19 Spring Framework :: Импорт контекста Часто удобно разбивать контекст на несколько файлов:

20 Spring Framework :: Подключение property- файлов к xml-контексту <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root jdbc.properties:

21 Spring Framework :: Создание псевдонимов После такой инструкции бин с именем originalName будет также доступен под именем aliasName; Такая необходимость часто возникает, когда архитектура приложения изначально создана с учетом возможности расширения, но при этом пока в конкретных разделах такой необходимости не возникает (и, соответственно, нет смысла плодить дополнительные объекты).

22 Spring Framework :: DI Внедрение зависимости через конструктор public class ConstructorInjection { private Dependency dep; private String descr; public ConstructorInjection(Dependency dep, String descr) { this.dep = dep; this.descr = descr; }

23 Spring Framework :: Constructor DI Циклическая зависимость: При Constructor DI для этих классов – BeanCurrentlyInCreationException Решение – в одном или обоих классах заменить Constructor DI на Setter DI

24 Spring Framework :: Setter DI public class SetterInjection { private Dependency dep; private String descr; public void setDep(Dependency dep) { this.dep = dep; } public void setDescr(String descr) { this.descr = descr; }

25 Spring Framework :: Autowiring Пример: сервисный класс для получения информации о пользователях UserDirectory LDAPUserDirectory DatabaseUserDirectory MockUserDirectory class LoginManager { UserDirectory userDirectory; } class UserDirectorySearch { UserDirectory userDirectory; } class UserInfo { UserDirectory userDirectory; } Пусть есть классы, которым нужна информация о пользователях: <bean id=userDirectorySearch class=UserDirectorySearch>

26 Spring Framework :: Autowiring Теперь включим автоматическое связывание (autowire) 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 также может быть сконфигурирован с использованием аннотаций; Основные типы поддерживаемых аннотаций: Для поддержки конфигурации через аннотации, в конфигурации Spring контейнера должно быть указано следующее свойство:

30 Spring Framework :: Использование Применяется только к SET методам бинов; Определяет что соответствующее свойство бина должно быть вычислено на этапе конфигурации (через конфигурацию или автоматическое связывание); Если соответствующее свойство не может быть задано – контейнер сгенерирует соответствующее исключение, что позволит избежать «неожиданных» NullPointerException в процессе работы системы; public class SimpleMovieLister { private MovieFinder public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; }

31 Spring Framework :: Использование Применяется к: –SET методам бинов; –Конструкторам; –Методам с несколькими параметрами; –Свойствам (в том числе, приватным); –К массивам и типизированным коллекциям (будут привязаны ВСЕ бины соответствующего класса) Возможно использование – в таком случае будет автоматически привязан бин с соответствующим ID; По-умолчанию генерируется исключение если не найден ни один подходящий бин. Это поведение может быть изменено с

32 Spring Framework :: Использование public class SimpleMovieLister { private MovieFinder public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; }

33 Spring Framework :: Использование Используется для задания Spring компонент без использования XML конфигурации Применяемся к классам Является базовым стереотипом для любого Spring-managed компонента Рекомендуется использовать более точные стереотипы: В большинстве случаев, если вы не уверены, какой именно стереотип использовать – Для автоматической регистрации бинов через аннотации необходимо указать следующую инструкцию в конфигурации контейнера:

34 Пример использования компонентов: package public class Adder { public int add(int a, int b) { return a + b; } package public class Calculator private Adder adder; public void makeAnOperation() { int r1 = adder.add(1,2); System.out.println("r1 = " + r1); } Spring Framework :: Использование аннотаций application_context.xml:

35 Spring Framework :: scope бинов Singleton –По-умолчанию –Один экземпляр бина в контейнере

36 Spring Framework :: scope бинов Prototype –Каждый раз при внедрении в другой бин или при вызове метода getBean() создается новый экземпляр бина

37 Spring Framework :: Жизненный цикл бина

38 Spring Framework :: Жизненный цикл бина Управление бином, реализуя интерфейсы из Spring Создание –Реализовать интерфейс InitializingBean –Переопределить метод afterPropertiesSet() Удаление –Реализовать интерфейс DisposableBean –Переопределить метод destroy()

39 Spring Framework :: Жизненный цикл бина Управление бином без зависимости от Spring в коде В нужный бин добавить методы для инициализации и/или удаления и указать их в объявлении бина: <bean id=example class=Example init-method=init" destroy-method=cleanup /> Можно задать методы для создания и/или удаления для всех бинов внутри контейнера: <beans default-init-method=init default-destroy-method=cleanup>

40 Spring Framework :: Доступ к ApplicationContext Чтобы получить доступ к контексту (например, для публикации своих событий) достаточно у бина имплементировать интерфейс ApplicationContextAware public class CommandManager implements ApplicationContextAware { private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }

41 Spring Framework :: События Получение стандартных событий: public class MyBean implements ApplicationListener { public void onApplicationEvent(ApplicationEvent event) { … } Публикация собственных событий: public 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 :: События Пример: регистрация нового сотрудника в компании. Возможные получатели события: - оповещение охранников, чтобы сделали пропуск - охранники подписываются на событие - дополнительно могут подписаться бухгалтерия, отдел кадров - допустим надо добавить новую функциональность: регистрировать новых сотрудников в базе данных - для этого нам достаточно создать класс для регистрации и подписаться на событие добавления сотрудника Преимущества: -Получателей может быть как угодно много; -Добавление получателя не добавляет зависимости: о получателе знает только он сам Недостатки: - Приводит к неявному поведению приложения

44 Spring Framework :: Локализация Интерфейс ApplicationContext наследует интерфейс MessageSource и, соответственно, предоставляет функциональность интернационализации (i18n) При загрузке автоматически ищет MessageSource бин в конфигурации (бин должен наследоваться от MessageSource и иметь id=messageSource) Если такой бин не может быть найден нигде в контексте – ApplicationContext создает экземпляр «заглушки» - DelegatingMessageSource для корректной обработки соответствующих методов

45 Spring Framework :: Локализация messages_en_US.properties customer.name=Ivan Ivanov, age : {0}, URL : {1} messages_ru_RU.properties customer.name=Иван Иванов, возраст : {0}, URL : {1} <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> locale\customer\messages Папка для расположения файлов: resources\locale\customer\ Locale.xml:

46 Spring Framework :: Локализация messages_en_US.properties customer.name=Ivan Ivanov, age : {0}, URL : {1} messages_ru_RU.properties customer.name=Иван Иванов, возраст : {0}, URL : {1} public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("locale.xml"); String name = context.getMessage("customer.name", new Object[] { 28, " }, Locale.US); System.out.println("Customer name (English) : " + name); String nameRussian = context.getMessage("customer.name", new Object[] {28, " }, Locale.RU); System.out.println("Customer name (Russian) : " + nameRussian); }

47 public class CustomerService implements MessageSourceAware { private MessageSource messageSource; public void setMessageSource(MessageSource messageSource) { this.messageSource = messageSource; } public void printMessage(){ ApplicationContext context = new ClassPathXmlApplicationContext("locale.xml"); String name = context.getMessage("customer.name", new Object[] { 28, " }, Locale.US); System.out.println("Customer name (English) : " + name); String nameRussian = context.getMessage("customer.name", new Object[] {28, " }, Locale.RU); System.out.println("Customer name (Russian) : " + nameRussian); } Spring Framework :: Локализация

48 Spring Framework :: Инициализция коллекций public class Customer { private List lists; private Set sets; private Map maps; private Properties pros; } 1

49 1 public class Customer { private List lists; private Set sets; private Map maps; private Properties pros; } Spring Framework :: Инициализция коллекций

50 public class Customer { private List lists; private Set sets; private Map maps; private Properties pros; } Spring Framework :: Инициализция коллекций

51 Spring Framework :: Инициализция коллекций public class Customer { private List lists; private Set sets; private Map maps; private Properties pros; }

52 Упражнения Работа со схемой Spring IoC – 20 мин – самостоятельная работа; – 10 мин – обсуждение;

53 <bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean"> <bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize"> Spring Framework :: Наследование свойств

54 child.admin s= Применимо к properties, list, set, map. Spring Framework :: Объединение коллекций

55 Spring Framework :: Пустые и null значения

56 <beans xmlns=" xmlns:p=" <bean name="p-namespace" class="com.example.ExampleBean" /> <bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane" /> Spring Framework :: p-namespace

57 Spring Framework :: Профили конфигурации GenericXmlApplicationContext ctx = 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 :: public class TransferServiceConfig DataSource public TransferService transferService() { return new DefaultTransferService(accountRepository(), feePolicy()); public AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource); public FeePolicy feePolicy() { return new ZeroFeePolicy(); } AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("dev"); // find and register classes within ctx.scan("com.bank.config.code"); ctx.refresh();

59 Упражнения 4: Разработка простейшего приложения: –50 мин – самостоятельная работа; –10 мин – обсуждение;

60 Вопросы!?