IoC - принцип взаимодействия
DI - реализация этого принципа
- BeanFactory - базовый интерфейс(базовый функционал). Ленивая инициализация, бины создаются только при необходимости;
- ApplicationContext - расширенный интерфейс(полный фарш, тяжеловесный). Инициализация всех бинов при запуске.
| Функционал | BeanFactory | ApplicationContext |
|---|---|---|
| Инициализация/автоматическое связывание бина | Да | Да |
| Автоматическая регистрация BeanPostProcessor | Нет | Да |
| Автоматическая регистрация BeanFactoryPostProcessor | Нет | Да |
| Удобный доступ к MessageSource(для i18n) | Нет | Да |
| ApplicationEvent публикация | Нет | Да |
- Singleton(Default) - возвращает единственный экземпляр. Ограничение на уровне контейнера, не на уровне класса;
- Prototype - новый экземпляр при каждом обращении;
- Request - жизненный цикл экземпляра ограничен единственным HTTP запросом; для каждого нового HTTP запроса создается новый экземпляр бина. Действует, только если вы используете web-aware ApplicationContext;
- Session - жизненный цикл экземпляра ограничен в пределах одной и той же HTTP Session. Действует, только если вы используете web-aware ApplicationContext;
- Global session - жизненный цикл экземпляра ограничен в пределах глобальной HTTP Session(обычно при использовании portlet контекста). Действует, только если вы используете web-aware ApplicationContext;
- Application - жизненный цикл экземпляра ограничен в пределах ServletContext. Действует, только если вы используете web-aware ApplicationContext;
Методы:
- init-method - инициализация конкретного бина;
- destroy-method - уничтожение конкретного бина;
- default-init-method - инициализация всех бинов по умолчанию;
- default-destroy-destroy - уничтожение всех бинов по умолчанию.
Интерфейсы:
- InitializingBean и DisposableBean - Инициализация и уничтожение бинов с помощью интерфейсов;
- BeanPostProcessor - единая точка обработки всех бинов при создании объектов(фильтр).
Использование интерфейсов жизненного цикла:
- Без дополнительных настроек;
- Для любых бинов;
- Минусы;
- Явное использование Spring API(Не будет работать без библиотек);
- В XML для каждого бина нужно отдельно прописывать;
- В XML не видно явной связи с Spring API.
Ленивая инициализация
Атрибут lazy-init. Создавать экземпляр бина при первом обращении.
Контекст принято делить по смыслу, например, подключение к БД или подключение к брокеру сообщений. Соединяются контексты с помощью тега import.
Пример:
<import resource="db_context.xml"/>Атрибут depends-on="someBean" позволяет связать два бина. Перед тем как инициализировать/создать бин сначала выполняется инициализация/создание бина указанного в depends-on.
Наследование бинов, абстрактные бины
Бины можно наследовать с помощью атрибута parent="someBean". У родительского бина не обязательно указывать класс. Поля можно переопределять в дочерних бинах. Что бы нельзя было по ошибке создать объект бина без класса следует делать бин абстрактным, для этого нужно добавить атрибут abstract="true". Не нужно путать наследование бинов и наследование классов, это разные вещи. Бины классов родителей объявлять не обязательно. Бин класса автоматически наследует все свойства классов родителей.
Проксирование в Spring реализовано двумя способами. С помощью CGLIB и JDK Dynamic Proxy.
CGLIB - библиотека для генерации кода. Используется для расширения java классов и реализации интерфейсов во время выполнения ПО. Повсеместно применяется в Spring(AOP, тестирование и пр.). Подключается через maven. Работает без интерфейсов в отличии от JDK Dynamic Proxy.
Шаблон проектирования proxy это оболочка для объекта(wrapper). Можно добавить какой либо функционал к объекта без внедрения в этот объект.
Внедрение методов
Три типа внедрения:
- Constructor injection;
- Setter injection;
- Method injection.
Method injection:
- Замена абстрактного метода нужной реализацией интерфейса;
- Способ использовать вместе Singleton и Prototype;
- Минусы - программирование на уровне XML.
Два способа внедрения методов:
<lookup-method>- позволяет во время выполнения заместить существующий метод (абстрактный или конкретный) новой реализацией, возвращающей определенный компонент из контекста Spring;<replaced-method>- позволяет во время выполнения заместить существующий метод (абстрактный или конкретный) новой реализацией.
Коллекции:
<list>- Список объектов(дублирование разрешено);<set>- Множество объектов(дублирование запрещено);<map>- Карта объектов(ключ - любой объект);<props>- Карта объектов(String - String);
SpEL - Spring Expression Language. Позволяет динамически, во время выполнения, внедрять:
- Объекты;
- Свойства объектов;
- Коллекции;
- Элементы коллекции;
- Простые значения;
- Математические функции;
- Системные параметры;
- Статические элементы классов;
- и др..
Можно управлять потоком программы без изменения кода. Позволяет сокращать программный код. Можно использовать с помощью аннотаций и XML.
- Все объекты должны быть загружены в контейнер!(желательно не создавать объекты вручную через new);
- Все объекты должны быть созданы с помощью bean;
- Цель - сокращение конфигурации XML;
- Автоматический поиск бина внутри контейнера для внедрения;
- Можно использовать в XML и через аннотации(боле предпочтительно);
- В XML автоматическое связывание нужно использовать осторожно(или вообще не использовать);
- Лучше через аннотацию
@Autowired(больше возможностей); - Атрибут
autowiredне наследует дочерние бины.
Минусы:
- Читаемость;
- Путаница, какой объект в итоге будет использоваться.
autowire="byType" - Атрибут тега bean для автоматического связывания, найти и связать по типу.
Если будет найдено несколько бинов подходящих для связывания при равных условиях случится исключение org.springframework.beans.factory.UnsatisfiedDependencyException. Контейнер не может определить какой бин нужно использовать.
Решение:
- Исключение дублирующих бинов из кандидатов для автоматического связывания путем добавления атрибута
autowire-candidates="false"; - Явное указывание бинов в XML переопределяет бины поиска(ручное указание имеет приоритет).
Аннотация - дополнительная информация(метаданные) внутри кода. Часто смешивают аннотации и XML для большей гибкости. По-умолчанию использование аннотаций для Spring контейнера отключено. Использование аннотаций Spring это привязка к фреймворку. Следует различать аннотации Spring и стандартные. Желательно чаще использовать стандартные аннотации(для лучшей переносимости кода).
- Уменьшение кода XML;
@Required- поле обязательно к заполнению на этапе конфигурации. Если поле не будет заполнено вылетит ошибка. Применяется к setter-методам;@Autowired- бин для автоматического связывания. В отличии от XML имеет возможность уточнять поиск бинов для внедрения;@Qualifier("t1000")- Уточнение для автоматического связывания. В данном случае указано имя бина. Так же можно добавить тег<qualifier value="t1000">в XML;<context:annotation-config/>- сообщает Spring контейнеру что используются аннотации. Без этого тега аннотации работать не будут;@Primaryиprimary="true"помечается приоритетный бин.
Аннотации @Autowired, @Inject, @Resource и @Value обрабатываются Spring реализацией BeanPostProcessor, поэтому мы не можем их применять в своих собственных BeanPostProcessor и BeanFactoryPostProcessor, а только лишь явной инициализацией через XML или @Bean метод.
Сканирование компонентов
Автоматически создаем компоненты на основе @Component или фильтра. Практически все конфигурации XML можно повторить с помощью аннотаций. Минус - меньше наглядности, нужно больше искать по классам.
<context:component-scan base-package="home.javabegin.training.spring"/>- сканирование бинов в указанном пакете. Бины должны быть помечены определенным образом;@Component- помечается класс для автоматического создания бина при сканировании. Общая аннотация. Её наследники@Repository,@Serviceи@Controller(рекомендуется использовать в тех случаях, когда мы можем отнести аннотируемый класс к определенному слою, например DAO);@Bean- Аннотация для методов. Метод должен возвращять тип бина. Аналог тега<bean>, возможность создания различных бинов на основе одного класса. Рекомендуется использовать вместе с@Configuration, а не с@Component;@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)- область видимости;@Configuration- класс с этой аннотацией говорит о том, что он является источником определения бинов. Аналог тега<beans>;@Lazy- ленивая инициализация;@ComponentScan- специальная аннотация для класса нашей конфигурации;@Import(AnotherConfiguration.class)- аннотация для подключения других классов-конфигураций, для разделения конфигурация по смыслу.
Если @Bean используется без @Configuration или @Component это называется обработка в легком режиме. Иначе, такие методы относятся к полному режиму обработки. В отличии от полного, в легком режиме @Bean методы не могут просто так объявлять внутренние зависимости. Поэтому, в основном предпочтительно работать в полном режиме, во избежании трудноуловимых ошибок.
Можно указать один или несколько псевдонимов для бина @Bean(name = "myBean"), @Bean(name = {"myBean1", "myBean2"}). @Description("Текстовое описание бина").
Аннотации для инициализации и уничтожения бинов из JSR-250:
@PostConstructаналогия методаafterPropertiesSet()из интерфейсаInitializingBean;@PreDestroyаналогия методаdestroy()из интерфейсаDisposablegBean.
Или @Bean(initMethod = "init", destroyMethod = "destroy").
Порядок вызовов:
- Методы с
@PostConstructи@PreDestroy; - Методы
afterPropertiesSet()иdestroy()из интерфейсовInitializingBeanиDisposablegBean; - Методы
@Bean(initMethod = "init", destroyMethod = "destroy").
Стандартные аннотации Java
- JSR-330, JSR-250, JSR-299;
@Resource@Inject@Named