SlideShare a Scribd company logo
Методики « Inversion of Control » и « Dependency Injection ». Применение в  Spring. Малышкин Фёдор ( [email_address] ) 27  июня 2008
Основы.  IoC. Концепция, лежащая в основе инверсии управления, часто выражается "голливудским принципом":  "Не звоните мне, я вам сам позвоню" . IoC переносит ответственность за выполнение действий с кода приложения на фреймворк.  В отношении конфигурирования это означает, что если в традиционных контейнерных архитектурах наподобие EJB, компонент может вызвать контейнер и спросить: "где объект Х, нужный мне для работы?", то в IoC сам контейнер выясняет, что компоненту нужен объект Х, и предоставляет его компоненту во время исполнения.
Основы.  DI В самом названии закладывается смысл – зависимости не создаются вашим кодом: они внедряются контейнером. Контейнер, среди прочего, может подставлять свои реализации, удовлетворяющие описанным интерфейсам. Это могут быть альтернативные реализации, прокси реальных объектов или иначе сконфигурированные старые реализации. Со стороны потребителя необходимо лишь приготовить пространство для зависимости ( property ) .
Зависимости. Класс А Класс Б Класс А Класс Б Поля, параметры Наследование, реализация Класс А Класс Б Класс В Транзитивные зависимости
Пример 1.  Login Manager. public   class  LoginManager  { private  UserList myUserList =  new  UserList(); ..... public   boolean  authenticateUser(String theUserName, String thePassword) { User aUser = myUserList.getUserByName(theUserName); return  thePassword.equals(aUser.getPassword()); } .... }
Пример 1. Недостатки. Если захочется каким-то образом изменить способ хранения пользователей, например, использовать базу данных или LDAP, придется переписать LoginManager, чтобы он создавал соответствующий класс для работы со списком пользователей.  Если предположить, что класс UserList зависим от платформы, например, использует JNI или пользуется каким-либо API, специфичным для какой-то платформы, то LoginManager будет также платформенно-зависимым.  Таким образом, из-за зависимости компонентов страдает  переносимость  и возможность их  повторного использования .
Пример 1. Улучшения. public   interface  UserStorage   { User getUserByName(String theUserName); } public   class  UserList  implements  UserStorage { .... }  public   class  LoginManager  { private  UserStorage myUserList =  new  UserList(); ..... public   boolean  authenticateUser(String theUserName, String thePassword) { User aUser = myUserList.getUserByName(theUserName); return  thePassword.equals(aUser.getPassword()); } .... }
Пример 1.  UML.  Начальная диаграмма классов.
Пример 1.  UML.  Диаграмма классов с вынесением зависимости.
Пример 1. Итоги. Итак, мы имеем прекрасные переносимые компоненты LoginManager, UserList, JdbcUserStorage, LdapUserStorage. Не стоит думать, что мы избавились от необходимости соединять их вместе.
Сборка. Для использования созданных нами компонентов необходим некий класс RuntimeAssembler, который будет делать грязную работу по соединению компонентов в единую систему.
Пример 2. Сборщик ( Composer, Assembler ) . public   final   class  SimpleSystemAssembler  { public   void  main(String[] args) { LoginManager aManager =  new  LoginManager(); aManager.setUserStorage( new  UserList()); aManager.authenticateUser("user", "test"); } } public   final   class  ComplexSystemAssembler  { public   void  main(String[] args) { LoginManager aManager =  new  LoginManager(); aManager.setUserStorage( new  JdbcUserStorage("jdbc:mysql:...", "mysql", "mysql")); aManager.authenticateUser("user", "test"); } }
Пример 2.  UML.
Сборка. Итоги. RuntimeAssembler-классы не предназначены для повторного использования или наследования от них. В больших системах эти классы максимально запутаны.  IoC-контейнеры как раз и предназначены для упрощения соединения компонентов. Все они позволяют использовать API и создавать RuntimeAssember-классы, при этом XML-конфигурация системы и RuntimeAssembler не понадобятся.
Service Locator Альтернативой паттерну вынесения зависимости (Dependency Injection) является паттерн  Service   Locator . Он широко используется в J2EE. Так, ServiceLocator может инкапсулировать все JNDI-вызовы J2EE-системы или создание (получение) UserStorage-реализации в нашем примере. Основным отличием Dependency Injection и Service Locator является то, что в Service Locator для получения реализации UserStorage используется вызов объекта ServiceLocator, в то время как в Dependency Injection ассемблер создает связь автоматически.
Пример 3.  Service Locator // Service Locator public  LoginManager() { myUserList = ServiceLocator.getUserStorage(); }
Пример 3.  UML.
Пример 3. Итоги Очевидно, что в паттерне ServiceLocator есть зависимость между LoginManager и ServiceLocator, в то время как LoginManager не зависит от RuntimeAssembler в Dependency Injection. Каждый может выбирать один из этих IoC-паттернов, в зависимости от своих нужд и задач.  Далее будет рассмотрен IoC-контейнер, реализованный в Spring Framework.
Spring SpringFramework  Spring Framework представляет собой набор готовых решений для использования всех основных Enterpise Java технологий — JDBC, ORM, JTA, Servlets/JSP, JMX и многих других. Абстрактные классы, фабрики и бины разработаны таким образом, чтобы программисту оставалось написать только свою логику
Spring.  Элементы.
Пример 4.  Spring Container. XML  файл контейнера может быть таким: <beans> <bean id=&quot;helloWorld&quot; class=&quot;samples.HelloWorldImpl&quot;> <property name=&quot;message&quot;> <value>Sergei</value> </property> </bean> </beans>
Пример 4.  Spring Container. public   class  HelloWorldImpl { private  String myMessage; public   void  setMessage(String theMessage) { myMessage = theMessage; } public   void  sayMessage() { System. out .println(&quot;Hello world!Hello &quot; + myMessage + &quot;!&quot;); } } public   class  Application { public   static   void  main(String[] args) { BeanFactory aBeanFactory =  new  XmlBeanFactory(&quot;sample-beans.xml&quot;); HelloWorld aHelloWorld = (HelloWorld) aBeanFactory.getBean(&quot;helloWorld&quot;); // выводит &quot;Hello world!Hello Sergei!&quot; в System.out aHelloWorld.sayMessage(); } }
Создание объектов В приведенном примере за конструирование объекта helloWorld отвечает контейнер – атрибут class элемента bean соответствует вызову конструктора без параметров.  Spring поддерживает широкий спектр механизмов создания объектов – вызов конструктора с параметрами или без, использование фабрик классов или фабричных методов.
Конструктор без параметра  <bean id=&quot;helloWorld&quot; class=&quot;sample.helloWorldImpl&quot;> .... </bean>
Конструктор с параметрами <beans> <bean id=&quot;exampleBean&quot; class=&quot;examples.ExampleBean&quot;> <constructor-arg> <ref bean=&quot;anotherExampleBean&quot;/> </constructor-arg> <constructor-arg> <ref bean=&quot;yetAnotherBean&quot;/> </constructor-arg> <constructor-arg type=&quot;int&quot;> <value>1</value> </constructor-arg> </bean> <bean id=&quot;anotherExampleBean&quot; class=&quot;examples.AnotherBean&quot;/> <bean id=&quot;yetAnotherBean&quot; class=&quot;examples.YetAnotherBean&quot;/> </beans>
Фабричный метод <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <beans> <bean id=&quot;exampleBean&quot; class=&quot;examples.ExampleBean&quot; factory-method=&quot;createInstance&quot;> <constructor-arg> <ref bean=&quot;anotherExampleBean&quot;/> </constructor-arg> <constructor-arg> <ref bean=&quot;yetAnotherBean&quot;/> </constructor-arg> <constructor-arg> <value>1</value> </constructor-arg> </bean> <bean id=&quot;anotherExampleBean&quot; class=&quot;examples.AnotherBean&quot;/> <bean id=&quot;yetAnotherBean&quot; class=&quot;examples.YetAnotherBean&quot;/> </beans>
Фабрика классов <beans> <bean id=&quot;exampleBean&quot; factory-bean=&quot;factory&quot; factory-method=&quot;createInstance&quot;> <constructor-arg> <ref bean=&quot;anotherExampleBean&quot;/> </constructor-arg> <constructor-arg> <ref bean=&quot;yetAnotherBean&quot;/> </constructor-arg> <constructor-arg> <value>1</value> </constructor-arg> </bean> <bean id=&quot;anotherExampleBean&quot; class=&quot;examples.AnotherBean&quot;/> <bean id=&quot;yetAnotherBean&quot; class=&quot;examples.YetAnotherBean&quot;/> <bean id=&quot;factory&quot; class=&quot;examples.UserFactory&quot;/> </beans>
Установка зависимостей и свойств Возникает вопрос: &quot;Какие типы данных могут быть установлены при помощи элемента property?&quot;, - ответ: &quot;Любые&quot;.  Spring использует технологию JavaBeans для установки свойств объектов, эта технология частично используется в JSP для установки свойств типа String и примитивных типов, но в Spring она используется гораздо шире – интерфейс  PropertyEditor  позволяет устанавливать значения свойств любых типов.  Поддерживаются стандартные коллекции из java.util: List, Set, Map, Properties, а также ссылки на объекты в контейнере по имени и значение null.
Установка зависимостей и свойств java.util.Properties – задается элементом props, отдельные свойства добавляются при помощи вложенного элемента prop, где атрибут key задает имя свойства, а текст внутри – значение.  java.util.Map – задается элементом map, отдельные элементы добавляются при помощи вложенного элемента entry, где атрибут key задает имя свойства, а значение – это значение внутреннего элемента. Внутренний элемент entry может представлять любой объект, в том числе и Map.  java.util.List, java.util.Set – представляются элементами list и set соответственно. Каждый внутренний элемент представляет собой значение элемента списка (множества).  ссылка на объект из контейнера – представляется элементом ref, причем ссылка на объект, определенный в том же файле, использует атрибут local, а в любом из конфигурационных файлов – bean.  Значение null соответствует литералу null.
Итоги Избавление от зависимости от конкретной реализации обладает следующими преимуществами: Повышается тестируемость кода. Вместо конкретной реализации всегда можно подсунуть  Mock. При написании распределенного приложения достаточно реализовать специфичную для клиента версию контракта (интерфейса). В том случае, когда «клиент» напрямую зависит от «другого»   класса, существует большая опасность завязаться на особенности конкретной реализации «другого» класса. Таким образом, изменения в реализации «другого» могут отразится и на «клиенте», и вызвать в нем так же ряд изменений.
Ad

Recommended

JavaScript Базовый. Занятие 03.
JavaScript Базовый. Занятие 03.
Igor Shkulipa
 
The Best Portlet
The Best Portlet
Alexey Zavizionov
 
Автоматизация и Selenium IDE
Автоматизация и Selenium IDE
ISsoft
 
JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.
Igor Shkulipa
 
Dependency Injection на примере Unity и NInject
Dependency Injection на примере Unity и NInject
akrakovetsky
 
Java 9 - Back to the Future
Java 9 - Back to the Future
Леонид Ставила
 
VAMR ACADEMY Второе занятие
VAMR ACADEMY Второе занятие
mixARConference
 
Автоматизация UI тестирования под Windows и Windows Phone
Автоматизация UI тестирования под Windows и Windows Phone
CodeFest
 
Что нового в Visual Studio 2010 и .Net 4.0
Что нового в Visual Studio 2010 и .Net 4.0
akrakovetsky
 
Поговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языка
Alexander Kucherenko
 
WTF Code @ jug.lv
WTF Code @ jug.lv
Andrei Solntsev
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщики
Andrey Karpov
 
JavaScript Базовый. Занятие 04.
JavaScript Базовый. Занятие 04.
Igor Shkulipa
 
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
Sergey Nemchinsky
 
обработка исключений в Java
обработка исключений в Java
metaform
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
zfconfua
 
введение в Javascript
введение в Javascript
inqubick
 
Dependency injection
Dependency injection
GetDev.NET
 
Сервлеты
Сервлеты
Unguryan Vitaliy
 
Введение в hibernate
Введение в hibernate
Unguryan Vitaliy
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0
matroskin1980
 
Средства разработки web приложений (Web frameworks)
Средства разработки web приложений (Web frameworks)
Fedor Malyshkin
 
XPath локаторы в Selenium WebDriver
XPath локаторы в Selenium WebDriver
Илья Кожухов
 
Selenium vs AJAX
Selenium vs AJAX
Alexei Barantsev
 
Unit тесты java
Unit тесты java
Vadim Lyakhovets
 
Опыт тестирования API САПР платформы
Опыт тестирования API САПР платформы
SQALab
 
Основы Java. 5. Databases
Основы Java. 5. Databases
Sergey Nemchinsky
 
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf Conference
 
Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)
Fedor Malyshkin
 
Django шахрай. версия 4
Django шахрай. версия 4
smikler
 

More Related Content

What's hot (19)

Что нового в Visual Studio 2010 и .Net 4.0
Что нового в Visual Studio 2010 и .Net 4.0
akrakovetsky
 
Поговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языка
Alexander Kucherenko
 
WTF Code @ jug.lv
WTF Code @ jug.lv
Andrei Solntsev
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщики
Andrey Karpov
 
JavaScript Базовый. Занятие 04.
JavaScript Базовый. Занятие 04.
Igor Shkulipa
 
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
Sergey Nemchinsky
 
обработка исключений в Java
обработка исключений в Java
metaform
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
zfconfua
 
введение в Javascript
введение в Javascript
inqubick
 
Dependency injection
Dependency injection
GetDev.NET
 
Сервлеты
Сервлеты
Unguryan Vitaliy
 
Введение в hibernate
Введение в hibernate
Unguryan Vitaliy
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0
matroskin1980
 
Средства разработки web приложений (Web frameworks)
Средства разработки web приложений (Web frameworks)
Fedor Malyshkin
 
XPath локаторы в Selenium WebDriver
XPath локаторы в Selenium WebDriver
Илья Кожухов
 
Selenium vs AJAX
Selenium vs AJAX
Alexei Barantsev
 
Unit тесты java
Unit тесты java
Vadim Lyakhovets
 
Опыт тестирования API САПР платформы
Опыт тестирования API САПР платформы
SQALab
 
Основы Java. 5. Databases
Основы Java. 5. Databases
Sergey Nemchinsky
 
Что нового в Visual Studio 2010 и .Net 4.0
Что нового в Visual Studio 2010 и .Net 4.0
akrakovetsky
 
Поговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языка
Alexander Kucherenko
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщики
Andrey Karpov
 
JavaScript Базовый. Занятие 04.
JavaScript Базовый. Занятие 04.
Igor Shkulipa
 
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
Шаблоны разработки ПО. Часть 3. Шаблоны GoF
Sergey Nemchinsky
 
обработка исключений в Java
обработка исключений в Java
metaform
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
zfconfua
 
введение в Javascript
введение в Javascript
inqubick
 
Dependency injection
Dependency injection
GetDev.NET
 
Введение в hibernate
Введение в hibernate
Unguryan Vitaliy
 
Alexander manuhin selenium_php_v2.0
Alexander manuhin selenium_php_v2.0
matroskin1980
 
Средства разработки web приложений (Web frameworks)
Средства разработки web приложений (Web frameworks)
Fedor Malyshkin
 
XPath локаторы в Selenium WebDriver
XPath локаторы в Selenium WebDriver
Илья Кожухов
 
Опыт тестирования API САПР платформы
Опыт тестирования API САПР платформы
SQALab
 
Основы Java. 5. Databases
Основы Java. 5. Databases
Sergey Nemchinsky
 

Similar to Методики «Inversion of Control» и «Dependency Injection». Применение в Spring. (20)

ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf Conference
 
Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)
Fedor Malyshkin
 
Django шахрай. версия 4
Django шахрай. версия 4
smikler
 
бегун
бегун
HighLoad2009
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Kirill Chebunin
 
Selenium rc
Selenium rc
Юлия Мерцалова
 
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
Alexander Byndyu
 
Введение в Django
Введение в Django
Илья Барышев
 
C# Web. Занятие 11.
C# Web. Занятие 11.
Igor Shkulipa
 
бегун
бегун
HighLoad2009
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.
Igor Shkulipa
 
C++ осень 2012 лекция 6
C++ осень 2012 лекция 6
Technopark
 
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Глеб Тарасов
 
Zend Framework и Doctrine
Zend Framework и Doctrine
Stepan Tanasiychuk
 
Building corporate portals with liferay JEEConf 2011
Building corporate portals with liferay JEEConf 2011
Alexey Kakunin
 
Symfony2 practice
Symfony2 practice
Skorney
 
паттерны программирования
паттерны программирования
guestfc8ae0
 
Виталий Каторгин, Wamba
Виталий Каторгин, Wamba
Ontico
 
WordCamp Russia 2015: Фильтры и события в WordPress.
WordCamp Russia 2015: Фильтры и события в WordPress.
Igor Zinovyev
 
Mikhail Valkov_Antipatterns
Mikhail Valkov_Antipatterns
Ciklum
 
ZFConf 2010: Zend Framework and Doctrine
ZFConf 2010: Zend Framework and Doctrine
ZFConf Conference
 
Документирование исходных текстов (javadoc)
Документирование исходных текстов (javadoc)
Fedor Malyshkin
 
Django шахрай. версия 4
Django шахрай. версия 4
smikler
 
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Чуть сложнее чем Singleton: аннотации, IOC, АОП
Kirill Chebunin
 
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
ASP.NET MVC - как построить по-настоящему гибкое веб-приложение
Alexander Byndyu
 
C# Web. Занятие 11.
C# Web. Занятие 11.
Igor Shkulipa
 
C++ STL & Qt. Занятие 02.
C++ STL & Qt. Занятие 02.
Igor Shkulipa
 
C++ осень 2012 лекция 6
C++ осень 2012 лекция 6
Technopark
 
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Интуит. Разработка приложений для iOS. Лекция 7. Работа с сетью
Глеб Тарасов
 
Building corporate portals with liferay JEEConf 2011
Building corporate portals with liferay JEEConf 2011
Alexey Kakunin
 
Symfony2 practice
Symfony2 practice
Skorney
 
паттерны программирования
паттерны программирования
guestfc8ae0
 
Виталий Каторгин, Wamba
Виталий Каторгин, Wamba
Ontico
 
WordCamp Russia 2015: Фильтры и события в WordPress.
WordCamp Russia 2015: Фильтры и события в WordPress.
Igor Zinovyev
 
Mikhail Valkov_Antipatterns
Mikhail Valkov_Antipatterns
Ciklum
 
Ad

More from Fedor Malyshkin (7)

Monitoring and Load testing
Monitoring and Load testing
Fedor Malyshkin
 
XML Schema
XML Schema
Fedor Malyshkin
 
Технология создания веб-сервисов на базе стандарта JAX-WS & JAXB
Технология создания веб-сервисов на базе стандарта JAX-WS & JAXB
Fedor Malyshkin
 
Скриптовой язык Groovy и его применение в рамках разработки ПО
Скриптовой язык Groovy и его применение в рамках разработки ПО
Fedor Malyshkin
 
Распределённые приложения. Часть 1. «Клиент и ядро бизнес-логики»
Распределённые приложения. Часть 1. «Клиент и ядро бизнес-логики»
Fedor Malyshkin
 
Agile, SCRUM, Планирование – что в этом для программистов?
Agile, SCRUM, Планирование – что в этом для программистов?
Fedor Malyshkin
 
Борьба с ошибками (TDD)
Борьба с ошибками (TDD)
Fedor Malyshkin
 
Monitoring and Load testing
Monitoring and Load testing
Fedor Malyshkin
 
Технология создания веб-сервисов на базе стандарта JAX-WS & JAXB
Технология создания веб-сервисов на базе стандарта JAX-WS & JAXB
Fedor Malyshkin
 
Скриптовой язык Groovy и его применение в рамках разработки ПО
Скриптовой язык Groovy и его применение в рамках разработки ПО
Fedor Malyshkin
 
Распределённые приложения. Часть 1. «Клиент и ядро бизнес-логики»
Распределённые приложения. Часть 1. «Клиент и ядро бизнес-логики»
Fedor Malyshkin
 
Agile, SCRUM, Планирование – что в этом для программистов?
Agile, SCRUM, Планирование – что в этом для программистов?
Fedor Malyshkin
 
Борьба с ошибками (TDD)
Борьба с ошибками (TDD)
Fedor Malyshkin
 
Ad

Методики «Inversion of Control» и «Dependency Injection». Применение в Spring.

  • 1. Методики « Inversion of Control » и « Dependency Injection ». Применение в Spring. Малышкин Фёдор ( [email_address] ) 27 июня 2008
  • 2. Основы. IoC. Концепция, лежащая в основе инверсии управления, часто выражается &quot;голливудским принципом&quot;: &quot;Не звоните мне, я вам сам позвоню&quot; . IoC переносит ответственность за выполнение действий с кода приложения на фреймворк. В отношении конфигурирования это означает, что если в традиционных контейнерных архитектурах наподобие EJB, компонент может вызвать контейнер и спросить: &quot;где объект Х, нужный мне для работы?&quot;, то в IoC сам контейнер выясняет, что компоненту нужен объект Х, и предоставляет его компоненту во время исполнения.
  • 3. Основы. DI В самом названии закладывается смысл – зависимости не создаются вашим кодом: они внедряются контейнером. Контейнер, среди прочего, может подставлять свои реализации, удовлетворяющие описанным интерфейсам. Это могут быть альтернативные реализации, прокси реальных объектов или иначе сконфигурированные старые реализации. Со стороны потребителя необходимо лишь приготовить пространство для зависимости ( property ) .
  • 4. Зависимости. Класс А Класс Б Класс А Класс Б Поля, параметры Наследование, реализация Класс А Класс Б Класс В Транзитивные зависимости
  • 5. Пример 1. Login Manager. public class LoginManager { private UserList myUserList = new UserList(); ..... public boolean authenticateUser(String theUserName, String thePassword) { User aUser = myUserList.getUserByName(theUserName); return thePassword.equals(aUser.getPassword()); } .... }
  • 6. Пример 1. Недостатки. Если захочется каким-то образом изменить способ хранения пользователей, например, использовать базу данных или LDAP, придется переписать LoginManager, чтобы он создавал соответствующий класс для работы со списком пользователей. Если предположить, что класс UserList зависим от платформы, например, использует JNI или пользуется каким-либо API, специфичным для какой-то платформы, то LoginManager будет также платформенно-зависимым. Таким образом, из-за зависимости компонентов страдает переносимость и возможность их повторного использования .
  • 7. Пример 1. Улучшения. public interface UserStorage { User getUserByName(String theUserName); } public class UserList implements UserStorage { .... } public class LoginManager { private UserStorage myUserList = new UserList(); ..... public boolean authenticateUser(String theUserName, String thePassword) { User aUser = myUserList.getUserByName(theUserName); return thePassword.equals(aUser.getPassword()); } .... }
  • 8. Пример 1. UML. Начальная диаграмма классов.
  • 9. Пример 1. UML. Диаграмма классов с вынесением зависимости.
  • 10. Пример 1. Итоги. Итак, мы имеем прекрасные переносимые компоненты LoginManager, UserList, JdbcUserStorage, LdapUserStorage. Не стоит думать, что мы избавились от необходимости соединять их вместе.
  • 11. Сборка. Для использования созданных нами компонентов необходим некий класс RuntimeAssembler, который будет делать грязную работу по соединению компонентов в единую систему.
  • 12. Пример 2. Сборщик ( Composer, Assembler ) . public final class SimpleSystemAssembler { public void main(String[] args) { LoginManager aManager = new LoginManager(); aManager.setUserStorage( new UserList()); aManager.authenticateUser(&quot;user&quot;, &quot;test&quot;); } } public final class ComplexSystemAssembler { public void main(String[] args) { LoginManager aManager = new LoginManager(); aManager.setUserStorage( new JdbcUserStorage(&quot;jdbc:mysql:...&quot;, &quot;mysql&quot;, &quot;mysql&quot;)); aManager.authenticateUser(&quot;user&quot;, &quot;test&quot;); } }
  • 14. Сборка. Итоги. RuntimeAssembler-классы не предназначены для повторного использования или наследования от них. В больших системах эти классы максимально запутаны. IoC-контейнеры как раз и предназначены для упрощения соединения компонентов. Все они позволяют использовать API и создавать RuntimeAssember-классы, при этом XML-конфигурация системы и RuntimeAssembler не понадобятся.
  • 15. Service Locator Альтернативой паттерну вынесения зависимости (Dependency Injection) является паттерн Service Locator . Он широко используется в J2EE. Так, ServiceLocator может инкапсулировать все JNDI-вызовы J2EE-системы или создание (получение) UserStorage-реализации в нашем примере. Основным отличием Dependency Injection и Service Locator является то, что в Service Locator для получения реализации UserStorage используется вызов объекта ServiceLocator, в то время как в Dependency Injection ассемблер создает связь автоматически.
  • 16. Пример 3. Service Locator // Service Locator public LoginManager() { myUserList = ServiceLocator.getUserStorage(); }
  • 18. Пример 3. Итоги Очевидно, что в паттерне ServiceLocator есть зависимость между LoginManager и ServiceLocator, в то время как LoginManager не зависит от RuntimeAssembler в Dependency Injection. Каждый может выбирать один из этих IoC-паттернов, в зависимости от своих нужд и задач. Далее будет рассмотрен IoC-контейнер, реализованный в Spring Framework.
  • 19. Spring SpringFramework Spring Framework представляет собой набор готовых решений для использования всех основных Enterpise Java технологий — JDBC, ORM, JTA, Servlets/JSP, JMX и многих других. Абстрактные классы, фабрики и бины разработаны таким образом, чтобы программисту оставалось написать только свою логику
  • 21. Пример 4. Spring Container. XML файл контейнера может быть таким: <beans> <bean id=&quot;helloWorld&quot; class=&quot;samples.HelloWorldImpl&quot;> <property name=&quot;message&quot;> <value>Sergei</value> </property> </bean> </beans>
  • 22. Пример 4. Spring Container. public class HelloWorldImpl { private String myMessage; public void setMessage(String theMessage) { myMessage = theMessage; } public void sayMessage() { System. out .println(&quot;Hello world!Hello &quot; + myMessage + &quot;!&quot;); } } public class Application { public static void main(String[] args) { BeanFactory aBeanFactory = new XmlBeanFactory(&quot;sample-beans.xml&quot;); HelloWorld aHelloWorld = (HelloWorld) aBeanFactory.getBean(&quot;helloWorld&quot;); // выводит &quot;Hello world!Hello Sergei!&quot; в System.out aHelloWorld.sayMessage(); } }
  • 23. Создание объектов В приведенном примере за конструирование объекта helloWorld отвечает контейнер – атрибут class элемента bean соответствует вызову конструктора без параметров. Spring поддерживает широкий спектр механизмов создания объектов – вызов конструктора с параметрами или без, использование фабрик классов или фабричных методов.
  • 24. Конструктор без параметра <bean id=&quot;helloWorld&quot; class=&quot;sample.helloWorldImpl&quot;> .... </bean>
  • 25. Конструктор с параметрами <beans> <bean id=&quot;exampleBean&quot; class=&quot;examples.ExampleBean&quot;> <constructor-arg> <ref bean=&quot;anotherExampleBean&quot;/> </constructor-arg> <constructor-arg> <ref bean=&quot;yetAnotherBean&quot;/> </constructor-arg> <constructor-arg type=&quot;int&quot;> <value>1</value> </constructor-arg> </bean> <bean id=&quot;anotherExampleBean&quot; class=&quot;examples.AnotherBean&quot;/> <bean id=&quot;yetAnotherBean&quot; class=&quot;examples.YetAnotherBean&quot;/> </beans>
  • 26. Фабричный метод <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <beans> <bean id=&quot;exampleBean&quot; class=&quot;examples.ExampleBean&quot; factory-method=&quot;createInstance&quot;> <constructor-arg> <ref bean=&quot;anotherExampleBean&quot;/> </constructor-arg> <constructor-arg> <ref bean=&quot;yetAnotherBean&quot;/> </constructor-arg> <constructor-arg> <value>1</value> </constructor-arg> </bean> <bean id=&quot;anotherExampleBean&quot; class=&quot;examples.AnotherBean&quot;/> <bean id=&quot;yetAnotherBean&quot; class=&quot;examples.YetAnotherBean&quot;/> </beans>
  • 27. Фабрика классов <beans> <bean id=&quot;exampleBean&quot; factory-bean=&quot;factory&quot; factory-method=&quot;createInstance&quot;> <constructor-arg> <ref bean=&quot;anotherExampleBean&quot;/> </constructor-arg> <constructor-arg> <ref bean=&quot;yetAnotherBean&quot;/> </constructor-arg> <constructor-arg> <value>1</value> </constructor-arg> </bean> <bean id=&quot;anotherExampleBean&quot; class=&quot;examples.AnotherBean&quot;/> <bean id=&quot;yetAnotherBean&quot; class=&quot;examples.YetAnotherBean&quot;/> <bean id=&quot;factory&quot; class=&quot;examples.UserFactory&quot;/> </beans>
  • 28. Установка зависимостей и свойств Возникает вопрос: &quot;Какие типы данных могут быть установлены при помощи элемента property?&quot;, - ответ: &quot;Любые&quot;. Spring использует технологию JavaBeans для установки свойств объектов, эта технология частично используется в JSP для установки свойств типа String и примитивных типов, но в Spring она используется гораздо шире – интерфейс PropertyEditor позволяет устанавливать значения свойств любых типов. Поддерживаются стандартные коллекции из java.util: List, Set, Map, Properties, а также ссылки на объекты в контейнере по имени и значение null.
  • 29. Установка зависимостей и свойств java.util.Properties – задается элементом props, отдельные свойства добавляются при помощи вложенного элемента prop, где атрибут key задает имя свойства, а текст внутри – значение. java.util.Map – задается элементом map, отдельные элементы добавляются при помощи вложенного элемента entry, где атрибут key задает имя свойства, а значение – это значение внутреннего элемента. Внутренний элемент entry может представлять любой объект, в том числе и Map. java.util.List, java.util.Set – представляются элементами list и set соответственно. Каждый внутренний элемент представляет собой значение элемента списка (множества). ссылка на объект из контейнера – представляется элементом ref, причем ссылка на объект, определенный в том же файле, использует атрибут local, а в любом из конфигурационных файлов – bean. Значение null соответствует литералу null.
  • 30. Итоги Избавление от зависимости от конкретной реализации обладает следующими преимуществами: Повышается тестируемость кода. Вместо конкретной реализации всегда можно подсунуть Mock. При написании распределенного приложения достаточно реализовать специфичную для клиента версию контракта (интерфейса). В том случае, когда «клиент» напрямую зависит от «другого» класса, существует большая опасность завязаться на особенности конкретной реализации «другого» класса. Таким образом, изменения в реализации «другого» могут отразится и на «клиенте», и вызвать в нем так же ряд изменений.