Dependency Injection в Java на примере эволюции Spring — Guice — CDI/Weld
Upcoming SlideShare
Loading in...5
×
 

Dependency Injection в Java на примере эволюции Spring — Guice — CDI/Weld

on

  • 489 views

Открытый семинар для студентов в компании CUSTIS (23 мая 2013). ...

Открытый семинар для студентов в компании CUSTIS (23 мая 2013).

Лектор: Сергей Кошель, ведущий разработчик Java, аналитик.

Аннотация: Из этого семинара вы узнаете о практическом применении паттерна Dependency Injection в мире Java и предоставляемых им возможностях на примере развития DI-фреймворков: от Spring и Guice до CDI/Weld. Формат встречи – динамичный с элементами Live Coding и демонстрацией особенностей реализации.

Видеозапись семинара: https://vimeo.com/67125102.

Statistics

Views

Total Views
489
Views on SlideShare
489
Embed Views
0

Actions

Likes
0
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Dependency Injection в Java на примере эволюции Spring — Guice — CDI/Weld Dependency Injection в Java на примере эволюции Spring — Guice — CDI/Weld Presentation Transcript

  • Dependency Injection в Javaна примере эволюцииSpring – Guice – CDI/WeldСергей КошельВедущий разработчик Java23 мая 2013 года
  • Разрабатываем адаптерПреобразование2/36
  • Первая версияSimpleConverterFileSource DatabaseStorageAdapter3/36
  • Первая версия+ Работать будет− Невозможно написать unit-тестpublic class Adapter {public void processMessage() {final FileSource fileSource = new FileSource();final SimpleConverter simpleConverter = new SimpleConverter();final DatabaseStorage databaseStorage = new DatabaseStorage();final Message inputMessage = fileSource.getMessage();final Message convertedMessage = simpleConverter.convert(inputMessage);databaseStorage.store(convertedMessage);}}4/36
  • Выделяем интерфейсыMockConverterMockSource MockStorageFileSourceSimpleConverterDatabaseStorageSourceConverterStorageAdapter 5/36
  • И добавляем фабрикиpublic class Adapter {public void processMessage() {final Source source = SourceFactory.getSource();final Converter converter = ConverterFactory.getConverter();final Storage storage = StorageFactory.getStorage();final Message inputMessage = source.getMessage();final Message convertedMessage = converter.convert(inputMessage);storage.store(convertedMessage);}}6/36
  • Пишем тест@Testpublic void processMessage() throws Exception {SourceFactory.setSource(new MockSource("Hello from test!"));StorageFactory.setStorage(new MockStorage());final Adapter adapter = new Adapter();adapter.processMessage();// assert that...}+ Получилось написать тест− Статический (глобальный) контекст− Много бойлерплейта− Зависимости неочевидны7/36
  • Избавляемся от фабрикpublic class Adapter {private Source source;private Converter converter;private Storage storage;public void setSource(Source source) {…}public void setConverter(Converter converter) {…}public void setStorage(Storage storage) {…}public void processMessage() {final Message inputMessage = source.getMessage();final Message convertedMessage = converter.convert(inputMessage);storage.store(convertedMessage);}}8/36
  • Переписываем тест@Testpublic void processMessage() throws Exception {final Adapter adapter = new Adapter();adapter.setSource(new MockSource("Hello from test!"));adapter.setConverter(new SimpleConverter());adapter.setStorage(new MockStorage());adapter.processMessage();// assert that...}+ Получилось:Setter based Dependency Injection by Hand9/36
  • Последний штрихpublic class Adapter {private final Source source;private final Converter converter;private final Storage storage;public Adapter(Source source, Converter converter, Storage storage) {this.source = source;this.converter = converter;this.storage = storage;}public void processMessage() {…}}10/36
  • Dependency Injection (DI) Паттерн проектирования (design pattern) О компонентах и их зависимостях Позволяет отделить объявлениезависимости от разрешения зависимости(и в пространстве, и во времени) Является частью более общего принципаInversion of Control (Hollywood principle –«Dont call us, well call you».)11/36
  • Причем тут тесты? Тесты не самоцель, но… С одной стороны, практически,DI позволяет проще писатьтестопригодный код А с другой стороны, концептуально,тесторигодность кода являетсяиндикатором хорошей слабосвязаннойархитектуры (loose coupling) В конечном итоге DI помогает удобнееписать слабосвязный код12/36
  • Можно было пойти другим путемpublic class Adapter {public void processMessage() {final Source source = UniversalFactory.get("source", Source.class);final Converter converter = UniversalFactory.get("converter",Converter.class);final Storage storage = UniversalFactory.get("storage", Storage.class);final Message inputMessage = source.getMessage();final Message convertedMessage = converter.convert(inputMessage);storage.store(convertedMessage);}}+ Получилось: Service Locator13/36
  • Паттерны DI и SLчасто противопоставляютсяDI зависимости определяет статически Проще разобраться в связях Компилятор многое может проверитьи подсказать Но иногда это является ограничениемSL – динамически Взаимосвязи запутаны, проще ошибиться Но иногда без этого не обойтись14/36
  • IoC-контейнерАвтоматизирует DI Разрешает граф зависимостей Конструирует компоненты по метаописаниюзависимостейИ привносит еще много полезностей Управление жизненным циклом Управление конфигурацией AOP …15/36
  • DisclaimerАвтор не в коем случае не имеетцели принизить один фреймворкза счет другого16/36
  • Spring Framework17/36
  • Описываем зависимости<?xml version="1.0" encoding="UTF-8"?><beans …><bean id="adapter" class="custis.seminars.diinjava.spring.Adapter" ><property name="source" ref="source"/><property name="converter" ref="converter"/><property name="storage" ref="storage"/></bean><bean id="source" class="custis.seminars.diinjava.spring.FileSource" /><bean id="converter" class="custis.seminars.diinjava.spring.SimpleConverter"/><bean id="storage" class="custis.seminars.diinjava.spring.DatabaseStorage"/></beans>* Похоже на императив, но это декларатив18/36
  • Запускаем контейнерfinal ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring-config.xml");adapter = applicationContext.getBean("adapter", Adapter.class);+ Код адаптера не изменился+ …нет зависимости от Spring’а+ …не надо его писать в каком-либоспециальном стиле19/36
  • Autowiring<bean id="adapter" class="custis.seminars.diinjava.autowiring.Adapter"autowire="byType" />20/36
  • Lifecycle Management singleton – создается один экземпляр prototype – создается отдельный экземплярпри каждом обращении<bean id="adapter" class="custis.seminars.diinjava.autowiring.Adapter"autowire="byType"scope="singleton"init-method="init"destroy-method="close" />[…]applicationContext.destroy();21/36
  • Метаданные в компоненте@Scope(SCOPE_SINGLETON)public class Adapter {private Source source;private Converter converter;private Storage storage;@Autowiredpublic void setSource(Source source) {…}@Autowiredpublic void setConverter(Converter converter) {…}@Autowired(required = false)public void setStorage(Storage storage) {…}@PostConstructpublic void init() {…}@PreDestroypublic void close() {…}} 22/36
  • Выбормежду несколькими реализациями23/36<bean id="source" class="custis.seminars.diinjava.autowiring.FileSource" />@Autowired@Qualifier("source")public void setSource(Source source) {…}− Легко ошибиться, и проявится это только в рантайме
  • Google Guice24/36
  • Pure Java configpublic class AdapterModule extends AbstractModule {@Overrideprotected void configure() {bind(SimpleConverter.class);bind(Source.class).to(FileSource.class);bind(Storage.class).toInstance(new DatabaseStorage());}}final Injector injector = Guice.createInjector(new AdapterModule());adapter = injector.getInstance(Adapter.class);25/36
  • Annotation based@Singletonpublic class Adapter {private final Source source;private final Converter converter;private final Storage storage;@Injectpublic Adapter(Source source, Converter converter, Storage storage) {this.source = source;this.converter = converter;this.storage = storage;}public void processMessage() {…}}* Зависимость от аннотаций, но они стандартные26/36
  • Pure Java configpublic class AdapterModule extends AbstractModule {@Overrideprotected void configure() {…}@ProvidesSource fileSource() {return new FileSource();}}* В Spring 3.0 появился JavaConfig27/36
  • Provider interfacepublic interface Provider <T> {T get();}bind(Validator.class).to(SimpleValidator.class);public class Adapter {private Provider<Validator> validator;@Injectpublic void setValidator(Provider<Validator> validator) {…}public void processMessage() {...validator.get().validate(inputMessage);...}}28/36
  • Provider interfaceКогда нужно… отложить создание (тяжелое, условное) много экземпляров (the new «new») вложить более узкий скоуп в широкий29/36
  • Выбормежду несколькими реализациями30/36@BindingAnnotation@Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)public @interface FileBased {}@Injectpublic Adapter(@FileBased Source source, Converter converter, Storage storage) {…}bind(Source.class).annotatedWith(FileBased.class).to(FileSource.class);+ Typesafe – компилятор проверит
  • CDI/WeldJSR 299: Contexts and Dependency Injectionfor the Java EE platformWeld – reference implementationfor JSR-29931/36
  • CDI Конфигурация похожа на Guice Нет DSL — используется @Produceи сканирование classpath Стандартизирует @Inject, @Sengleton,Provider<T> и т. д. Тесно интегрируется с EJB-контейнером32/36
  • Instance – Provider на стероидах Расширяет возможности ProviderInstance<T> extends Provider<T> …опциональные зависимостиif (instance.isUnsatisfied()) {…} …многозначные зависимостиif (instance.isAmbiguous()) {for (T t : instance) {...}} …динамическое разрешение зависимостей (SL)adapter = instance.select(Adapter.class).get();33/36
  • Event<T>public class Adapter {@InjectEvent<AdapterStarted> adapterStartedEvent;@PostConstructpublic void init() {adapterStartedEvent.fire(new AdapterStarted());}}public class AnyOtherManagedBean{public void onAdapterStart(@Observes AdapterStarted adapterStarted) {…}}34/36
  • О чем не рассказал AOP и method intercepting Генерализованные типы зависимостей Многозначные зависимости Scopes …35/36
  • Спасибо!Вопросы?Сергей Кошельskoshel@custis.ru36/36