Главная страница
Навигация по странице:

  • 16. Расскажите про аннотацию @Conditional

  • Аннотация Описание

  • 17. Расскажите про аннотацию @ComponentScan

  • 18. Расскажите про аннотацию @Profile

  • 19. Расскажите про ApplicationContext и BeanFactory, чем отличаются В каких случаях что стоит использовать

  • ApplicationContext vs. BeanFactory Feature

  • 20. Расскажите про жизненный цикл бина, аннотации @PostConstruct и @PreDestroy()

  • Жизненный цикл бинов 1. Парсирование конфигурации и создание BeanDefinition

  • Свойство Ссылка с описанием

  • 2. Настройка созданных BeanDefinition

  • 3. Создание кастомных FactoryBean (только для XML-конфигурации) 4. Создание экземпляров бинов

  • 5. Настройка созданных бинов

  • Именно на данном этапе создаются прокси стандартными BeanPostProcessor-ами.

  • 6. Бины готовы к использованию Их можно получить с помощью метода ApplicationContextgetBean(). 7. Закрытие контекста

  • Ызкштп. Оглавление Введение 61. Что такое инверсия контроля (IoC) и внедрение зависимостей (DI) Как они реализованы в


    Скачать 1.17 Mb.
    НазваниеОглавление Введение 61. Что такое инверсия контроля (IoC) и внедрение зависимостей (DI) Как они реализованы в
    АнкорЫзкштп
    Дата01.11.2021
    Размер1.17 Mb.
    Формат файлаpdf
    Имя файлаmetodichka_06_Spring (3).pdf
    ТипДокументы
    #260853
    страница2 из 5
    1   2   3   4   5
    actionHeroes;
    }
    @Configuration public class
    HeroesConfig
    {

    @Bean public
    List action
    ()
    {
    List result = new
    ArrayList<>(); result.add(
    new
    Terminator()); result.add(
    new
    Rambo()); return result;
    }
    }

    16. Расскажите про аннотацию @Conditional
    Источники:
    Spring API - @Conditional
    Spring API - Interface Condition
    Spring - Conditionally Include @Configuration Classes or @Bean Methods
    Baeldung - Custom Auto-Configuration with Spring Boot
    Habr - Использование Conditional в Spring
    Часто бывает полезно включить или отключить весь класс @Configuration, @Component или отдельные методы @Bean в зависимости от каких-либо условий.
    Аннотация @Conditional указывает, что компонент имеет право на регистрацию в контексте только тогда, когда все условия соответствуют. Может применяться:
    ❖ над классами прямо или косвенно аннотированными @Component, включая классы
    @Configuration;
    ❖ над методами @Bean;
    ❖ как мета-аннотация при создании наших собственных аннотаций-условий.
    Условия проверяются непосредственно перед тем, как должно быть зарегистрировано
    BeanDefinition компонента, и они могут помешать регистрации данного BeanDefinition. Поэтому нельзя допускать, чтобы при проверке условий мы взаимодействовали с бинами (которых еще не существует), с их BeanDefinition-ами можно.
    Условия мы определяем в специально создаваемых нами классах, которые должны имплементировать функциональный интерфейс Condition с одним единственным методом, возвращающим true или false: boolean matches
    (ConditionContext context, AnnotatedTypeMetadata metadata)
    Создав свой класс и переопределив в нем метод matches() с нашей логикой, мы должны передать этот класс в аннотацию @Conditional в качестве параметра:
    @Configuration
    @Conditional
    (OurConditionClass.class) class
    MySQLAutoconfiguration
    {
    //...
    }
    Для того, чтобы проверить несколько условий, можно передать в @Conditional несколько классов с условиями:
    @Bean
    @Conditional
    (HibernateCondition.class, OurConditionClass.class)
    Properties additionalProperties
    ()
    {
    //...
    }
    Если класс @Configuration помечен как @Conditional, то на все методы @Bean, аннотации @Import и аннотации @ComponentScan, связанные с этим классом, также будут распространяться указанные условия.
    Для более детальной настройки классов, аннотированных @Configuration, предлагается использовать интерфейс ConfigurationCondition.

    В одном классе - одно условие. Для создания более сложных условий можно использовать классы AnyNestedCondition, AllNestedConditions и NoneNestedConditions.
    В Spring Framework имеется множество готовых аннотаций (и связанных с ними склассами-условиями, имплементирующими интерфейс Condition), которые можно применять совместно над одним определением бина:
    Аннотация
    Описание
    ConditionalOnBean
    Условие выполняется, в случае если присутствует нужный бин в BeanFactory.
    ConditionalOnClass
    Условие выполняется, если нужный класс есть в classpath.
    ConditionalOnCloudPlatform
    Условие выполняется, когда активна определенная платформа.
    ConditionalOnExpression
    Условие выполняется, когда SpEL выражение вернуло положительное значение.
    ConditionalOnJava
    Условие выполняется, когда приложение запущено с определенной версией JVM.
    ConditionalOnJndi
    Условие выполняется, только если через JNDI доступен определенный ресурс.
    ConditionalOnMissingBean
    Условие выполняется, в случае если нужный бин отсутствует в контейнере.
    ConditionalOnMissingClass
    Условие выполняется, если нужный класс отсутствует в classpath.
    ConditionalOnNotWebApplication
    Условие выполняется, если контекст приложения не является веб контекстом.
    ConditionalOnProperty
    Условие выполняется, если в файле настроек заданы нужные параметры.
    ConditionalOnResource
    Условие выполняется, если присутствует нужный ресурс в classpath.
    ConditionalOnSingleCandidate
    Условие выполняется, если bean-компонент указанного класса уже содержится в контейнере и он единственный.
    ConditionalOnWebApplication
    Условие выполняется, если контекст приложения является веб контекстом.

    17. Расскажите про аннотацию @ComponentScan
    Источники:
    Spring - Automatically Detecting Classes and Registering Bean Definitions
    Baeldung - Spring Component Scanning
    Baeldung - Spring @ComponentScan – Filter Types
    Аннотация @ComponentScan используется вместе с аннотацией @Configuration для указания пакетов, которые мы хотим сканировать на наличие компонентов, из которых нужно сделать бины.
    @ComponentScan без аргументов указывает Spring по умолчанию сканировать текущий пакет и все его подпакеты. Текущий пакет - тот, в котором находится файл конфигурации с этой самой аннотацией @ComponentScan. В данном случае в контейнер попадут:
    ❖ бин конфигурационного класса;
    ❖ бины, объявленные в конфигурационном классе с помощью @Bean;
    ❖ все бины из пакета и его подпакетов.
    Аннотация @SpringBootApplication включает в себя аннотации @ComponentScan,
    @SpringBootConfiguration и @EnableAutoConfiguration, но это не мешает разместить её ещё раз отдельно для указания конкретного пакета.
    Если указать @ComponentScan с атрибутом basePackages, то это изменит пакет по умолчанию на указанный:
    @ComponentScan
    (basePackages =
    "com.baeldung.componentscan.springapp.animals"
    )
    @Configuration public class
    SpringComponentScanApp
    {
    // ...
    }
    Если указать @ComponentScan с атрибутом excludeFilters, то это позволит использовать фильтр и исключить ненужные классы из процесса сканирования:
    @ComponentScan
    (excludeFilters =
    @ComponentScan
    .Filter(type=FilterType.REGEX, pattern=
    "com\\.baeldung\\.componentscan\\.springapp\\.flowers\\..*"
    ))

    18. Расскажите про аннотацию @Profile
    Источники:
    Spring - Bean Definition Profiles
    Spring API - @Profile
    Baeldung - Spring Profiles
    Mkyong - Spring Profiles example
    Профили — это ключевая особенность Spring Framework, позволяющая нам относить наши бины к разным профилям (логическим группам), например, dev, test, prod.
    Мы можем активировать разные профили в разных средах, чтобы загрузить только те бины, которые нам нужны.
    Используя аннотацию @Profile, мы относим бин к конкретному профилю. Её можно применять на уровне класса или метода. Аннотация @Profile принимает в качестве аргумента имя одного или нескольких профилей. Она фактически реализована с помощью гораздо более гибкой аннотации @Conditional.
    Рассмотрим базовый сценарий - у нас есть бин, который должен быть активным только во время разработки, но не должен использоваться в продакшене. Мы аннотируем этот компонент с профилем «dev», и он будет присутствовать в контейнере только во время разработки - во время продакшена профиль dev просто не будет активен:
    @Component
    @Profile
    (
    "dev"
    ) public class
    DevDatasourceConfig
    В качестве быстрого обозначения имена профилей также могут начинаться с оператора
    NOT, например «!dev», чтобы исключить их из профиля. В приведенном ниже примере компонент активируется, только если профиль «dev» не активен:
    @Component
    @Profile
    (
    "!dev"
    ) public class
    DevDatasourceConfig
    Следующим шагом является активация нужного профиля для того, чтобы в контейнере были зарегистрированы только бины, соответствующие данному профилю. Одновременно могут быть активны несколько профилей.
    По умолчанию, если профиль бина не определен, то он относится к профилю “default”.
    Spring также предоставляет способ установить профиль по умолчанию, когда другой профиль не активен, используя свойство «spring.profiles.default».
    В Spring Boot есть возможность иметь один файл настроек application.properties, в котором будут основные настройки для всех профилей, и иметь по файлу настроек для каждого профиля application-dev.properties и application-prod.properties, содержащие свои собственные дополнительные настройки.

    19. Расскажите про ApplicationContext и BeanFactory, чем отличаются? В
    каких случаях что стоит использовать?
    Источники:
    Spring - The IoC Container
    Spring - BeanFactory or ApplicationContext?
    Baeldung - Difference Between BeanFactory and ApplicationContext
    BeanFactory
    BeanFactory — это интерфейс, который предоставляет механизм конфигурации, способный управлять объектами любого типа. В общем, BeanFactory предоставляет инфраструктуру конфигурации и основные функциональные возможности.
    BeanFactory легче по сравнению с ApplicationContext.
    ApplicationContext
    ApplicationContext является наследником BeanFactory и полностью реализует его функционал, добавляя больше специфических enterprise-функций.
    ApplicationContext vs. BeanFactory
    Feature
    BeanFactory
    ApplicationContext
    Bean instantiation/wiring
    Yes
    Yes
    Integrated lifecycle management
    No
    Yes
    Automatic
    BeanPostProcessor registration
    No
    Yes
    Automatic
    BeanFactoryPostProcessor registration
    No
    Yes
    Convenient
    MessageSource access (for internalization)
    No
    Yes
    Built-in
    ApplicationEvent publication mechanism
    No
    Yes
    1. ApplicationContext загружает все бины при запуске, а BeanFactory - по требованию.
    2. ApplicationContext расширяет BeanFactory и предоставляет функции, которые подходят для корпоративных приложений: a. поддержка внедрения зависимостей на основе аннотаций; b. удобный доступ к MessageSource (для использования в интернационализации
    ); c. публикация
    ApplicationEvent
    - для бинов, реализующих интерфейс
    ApplicationListener, с помощью интерфейса ApplicationEventPublisher; d. простая интеграция с функциями Spring AOP.
    3. ApplicationContext поддерживает автоматическую регистрацию BeanPostProcessor и
    BeanFactoryPostProcessor. Поэтому всегда желательно использовать ApplicationContext, потому что Spring 2.0 (и выше) интенсивно использует BeanPostProcessor.

    4. ApplicationContext поддерживает практически все типы scope для бинов, а BeanFactory поддерживает только два - Singleton и Prototype.
    5. В BeanFactory не будут работать транзакции и Spring AOP. Это может привести к путанице, потому что конфигурация с виду будет корректной.

    20. Расскажите про жизненный цикл бина, аннотации @PostConstruct и
    @PreDestroy()
    Источники:
    Spring - Introduction to the Spring IoC Container and Beans
    Spring API - BeanPostProcessor
    Shell26 - Bean
    Baeldung - PostConstruct and PreDestroy Annotations
    Spring-projects.ru - Урок 2: Введение в Spring IoC контейнер
    Habr - Этапы инициализации контекста
    Medium - Spring под капотом
    YouTube - Евгений Борисов — Spring-потрошитель, часть 1
    YouTube - Евгений Борисов — Spring-потрошитель, часть 2
    Жизненный цикл бинов
    1. Парсирование конфигурации и создание BeanDefinition
    Цель первого этапа — это создание всех BeanDefinition. Объекты BeanDefinition — это набор метаданных будущего бина, макет, по которому нужно будет создавать бин в случае необходимости. То есть для каждого бина создается свой объект BeanDefinition, в котором хранится описание того, как создавать и управлять этим конкретным бином. Проще говоря, сколько бинов в программе - столько и объектов BeanDefinition, их описывающих.
    BeanDefinition содержат (среди прочего) следующие метаданные:
    1. Имя класса с указанием пакета: обычно это фактический класс бина.
    2. Элементы поведенческой конфигурации бина, которые определяют, как бин должен вести себя в контейнере (scope, обратные вызовы жизненного цикла и т.д.).
    3. Ссылки на другие bean-компоненты, которые необходимы для его работы. Эти ссылки также называются зависимостями.
    4. Другие параметры конфигурации для установки во вновь созданном объекте - например, ограничение размера пула или количество соединений, используемых в бине, который управляет пулом соединений.
    Эти метаданные преобразуются в набор свойств, которые составляют каждое
    BeanDefinition. В следующей таблице описаны эти свойства:
    Свойство
    Ссылка с описанием
    Class
    Instantiating Beans
    Name
    Naming Beans
    Scope
    Bean Scopes
    Constructor arguments
    Dependency Injection
    Properties
    Dependency Injection
    Autowiring mode
    Autowiring Collaborators

    Lazy initialization mode
    Lazy-initialized Beans
    Initialization method
    Initialization Callbacks
    Destruction method
    Destruction Callbacks
    При конфигурации через аннотации с указанием пакета для сканирования или JavaConfig используется класс AnnotationConfigApplicationContext. Регистрируются все классы с
    @Configuration для дальнейшего парсирования, затем регистрируется специальный
    BeanFactoryPostProcessor, а именно BeanDefinitionRegistryPostProcessor, который при помощи класса ConfigurationClassParser парсирует JavaConfig, загружает описания бинов (BeanDefinition), создаёт граф зависимостей (между бинами) и создаёт:
    Map beanDefinitionMap = new
    ConcurrentHashMap<>(
    256
    );
    в которой хранятся все описания бинов, обнаруженных в ходе парсинга конфигурации.
    2. Настройка созданных BeanDefinition
    После первого этапа у нас имеется коллекция Map, в которой хранятся BeanDefinition-ы.
    BeanFactoryPostProcessor-ы на этапе создания BeanDefinition-ов могут их настроить как нам необходимо. BeanFactoryPostProcessor-ы могут даже настроить саму BeanFactory ещё до того, как она начнет работу по созданию бинов. В интерфейсе BeanFactoryPostProcessor всего один метод: public interface
    BeanFactoryPostProcessor
    { void postProcessBeanFactory
    (ConfigurableListableBeanFactory beanFactory)
    throws
    BeansException;
    }
    3. Создание кастомных FactoryBean (только для XML-конфигурации)
    4. Создание экземпляров бинов
    Сначала BeanFactory из коллекции Map с объектами BeanDefinition достаёт те из них, из которых создаёт все BeanPostProcessor-ы, необходимые для настройки обычных бинов.
    Создаются экземпляры бинов через BeanFactory на основе ранее созданных
    BeanDefinition.
    5. Настройка созданных бинов
    На данном этапе бины уже созданы, мы можем лишь их донастроить.
    Интерфейс BeanPostProcessor позволяет вклиниться в процесс настройки наших бинов до того, как они попадут в контейнер. ApplicationContext автоматически обнаруживает любые бины с реализацией BeanPostProcessor и помечает их как “post-processors” для того, чтобы создать их определенным способом. Например, в Spring есть реализации BeanPostProcessor-ов, которые обрабатывают аннотации @Autowired, @Inject, @Value и @Resource.
    Интерфейс несет в себе два метода: postProcessBeforeInitialization(Object bean, String beanName) и postProcessAfterInitialization(Object bean, String beanName). У обоих методов параметры абсолютно одинаковые. Разница только в порядке их вызова. Первый вызывается до init-метода, второй - после.

    Как правило, BeanPostProcessor-ы, которые заполняют бины через маркерные интерфейсы или тому подобное, реализовывают метод postProcessBeforeInitialization (Object bean, String beanName), тогда как BeanPostProcessor-ы, которые оборачивают бины в прокси, обычно реализуют postProcessAfterInitialization (Object bean, String beanName).
    Прокси — это класс-декорация над бином. Например, мы хотим добавить логику нашему бину, но джава-код уже скомпилирован, поэтому нам нужно на лету сгенерировать новый класс.
    Этим классом мы должны заменить оригинальный класс так, чтобы никто не заметил подмены.
    Есть два варианта создания этого класса:
    1. либо он должен наследоваться от оригинального класса (CGLIB) и переопределять его методы, добавляя нужную логику;
    2. либо он должен имплементировать те же самые интерфейсы, что и первый класс
    (Dynamic Proxy).
    По конвенции спринга, если какой-то из BeanPostProcessor-ов меняет что-то в классе, то он должен это делать на этапе postProcessAfterInitialization(). Таким образом мы уверены, что initMethod у данного бина, работает на оригинальный метод, до того, как на него накрутился прокси.
    Хронология событий:
    1. Сначала сработает метод postProcessBeforeInitialization() всех имеющихся
    BeanPostProcessor-ов.
    2. Затем, при наличии, будет вызван метод, аннотированный @PostConstruct.
    3. Если бин имплементирует InitializingBean, то Spring вызовет метод afterPropertiesSet() -
    не рекомендуется к использованию как устаревший.
    4. При наличии, будет вызван метод, указанный в параметре initMethod аннотации @Bean.
    5. В конце бины пройдут через postProcessAfterInitialization (Object bean, String beanName).
    Именно на данном этапе создаются прокси стандартными BeanPostProcessor-ами.
    Затем отработают наши кастомные BeanPostProcessor-ы и применят нашу логику к прокси-объектам. После чего все бины окажутся в контейнере, который будет обязательно обновлен методом refresh().
    6. Но даже после этого мы можем донастроить наши бины ApplicationListener-ами.
    7. Теперь всё.

    6. Бины готовы к использованию
    Их можно получить с помощью метода ApplicationContext#getBean().
    7. Закрытие контекста
    Когда контекст закрывается (метод close() из ApplicationContext), бин уничтожается.
    Если в бине есть метод, аннотированный @PreDestroy, то перед уничтожением вызовется этот метод.
    Если бин имплементирует DisposibleBean, то Spring вызовет метод destroy() - не
    рекомендуется к использованию как устаревший.
    Если в аннотации @Bean определен метод destroyMethod, то будет вызван и он.
    @PostConstruct
    Spring вызывает методы, аннотированные @PostConstruct, только один раз, сразу после инициализации свойств компонента. За данную аннотацию отвечает один из BeanPostProcessor- ов.
    Метод, аннотированный @PostConstruct, может иметь любой уровень доступа, может иметь любой тип возвращаемого значения (хотя тип возвращаемого значения игнорируется
    Spring-ом), метод не должен принимать аргументы. Он также может быть статическим, но преимуществ такого использования метода нет, т.к. доступ у него будет только к статическим полям/методам бина, и в таком случае смысл его использования для настройки бина пропадает.
    Одним из примеров использования @PostConstruct является заполнение базы данных.
    Например, во время разработки нам может потребоваться создать пользователей по умолчанию.
    1   2   3   4   5


    написать администратору сайта