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

  • Как заинжектить примитив

  • Как заинжектить коллекцию

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

  • Аннотация @Conditional указывает, что компонент имеет право на регистрацию в контексте только тогда, когда все условия соответствуют.

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

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

  • Расскажите про скоупы бинов Какой скоуп используется по умолчанию

  • Singleton

  • Request

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

  • Как спринг работает с транзакциями Расскажите про аннотацию

  • REQUIRES_NEW

  • MANDATORY

  • NOT_SUPPORTED

  • ОглавлениеCore


    Скачать 1.53 Mb.
    НазваниеОглавлениеCore
    Дата17.05.2023
    Размер1.53 Mb.
    Формат файлаpdf
    Имя файлаpolnaya_metodichka (1).pdf
    ТипДокументы
    #1138113
    страница22 из 25
    1   ...   17   18   19   20   21   22   23   24   25
    GreetingService должна быть установлена соответствующая аннотация @Qualifier:
    @Component
    @Qualifier("main")
    public class GreetingServiceImpl implements GreetingService {
    //...
    }
    @Primary тоже используется, чтобы отдавать предпочтение бину, когда есть несколько бинов одного типа, но в ней нельзя задать имя бина, она определяет значение по умолчанию, в то время как @Qualifier более специфичен.
    Если присутствуют аннотации @Qualifier и @Primary, то аннотация @Qualifier будет иметь приоритет.
    Как заинжектить примитив?
    Для этого можно использовать аннотацию @Value. Можно ставить над полем,
    конструктором, методом.
    Такие значения можно получать из property файлов, из бинов, и т. п.

    @Value("${some.key}")
    public String stringWithDefaultValue;
    В эту переменную будет внедрена строка, например, из property или из view.
    Кроме того, для внедрения значений можно использовать язык SpEL (Spring Expression
    Language).
    Как заинжектить коллекцию?
    Если внедряемый объект массив, коллекция или map с дженериком, то, используя аннотацию @Autowired, Spring внедрит все бины, подходящие по типу в этот массив (или другую структуру данных). В случае с map ключом будет имя бина.
    Используя аннотацию @Qualifier можно настроить тип искомого бина.
    Бины могут быть упорядочены, если вставляются в списки (не Set или Map) или массивы.
    Поддерживаются как аннотация @Order, так и интерфейс Ordered.
    Расскажите про аннотацию @Conditional
    Spring предоставляет возможность на основе используемого алгоритма включить или выключить определение бина или всей конфигурации через @Conditional, в качестве параметра которой указывается класс, реализующий интерфейс Condition, с единственным методом matches(ConditionContext var1, AnnotatedTypeMetadata var2), возвращающий boolean.
    Для создания более сложных условий можно использовать классы AnyNestedCondition,
    AllNestedConditions и NoneNestedConditions.
    Аннотация @Conditional указывает, что компонент имеет право на регистрацию в
    контексте только тогда, когда все условия соответствуют.
    Условия проверяются непосредственно перед тем, как должен быть зарегистрирован
    BeanDefinition компонента, и они могут помешать регистрации данного BeanDefinition.
    Поэтому при проверке условий нельзя допускать взаимодействия с бинами, которых еще не существует, с их BeanDefinition-ами можно.
    Для того, чтобы проверить несколько условий, можно передать в @Conditional несколько классов с условиями:
    @Conditional(HibernateCondition.class, OurConditionClass.class)
    Если класс @Configuration помечен как @Conditional, то на все методы @Bean, аннотации
    @Import и аннотации @ComponentScan, связанные с этим классом, также будут распространяться указанные условия.
    Расскажите про аннотацию @Profile
    Профили – это ключевая особенность Spring Framework, позволяющая относить бины к разным профилям (логическим группам), например, dev, local, test, prod.
    Можно активировать разные профили в разных средах, чтобы загрузить только те бины,
    которые нужны.

    Используя аннотацию @Profile относим бин к конкретному профилю. Ее можно применять на уровне класса или метода. Аннотация @Profile принимает в качестве аргумента имя одного или нескольких профилей. Она фактически реализована с помощью более гибкой аннотации
    @Conditional.
    Ее можно ставить на @Configuration и Component классы.
    Расскажите про жизненный цикл бина, аннотации @PostConstruct и
    @PreDestroy()
    1. Парсирование конфигурации и создание BeanDefinition.

    xml-конфигурация – ClassPathXmlApplicationContext(“context.xml”);

    конфигурация через аннотации с указанием пакета для сканирования –
    AnnotationConfigApplicationContext(“package.name”);

    конфигурация через аннотации с указанием класса (или массива классов),
    помеченного аннотацией
    @Configuration

    AnnotationConfigApplicationContext(JavaConfig.class), этот способ конфигурации называется JavaConfig;

    groovy-конфигурация – GenericGroovyApplicationContext(“context.groovy”).
    Если заглянуть внутрь AnnotationConfigApplicationContext, то можно увидеть два поля.
    private final AnnotatedBeanDefinitionReader reader;
    private final ClassPathBeanDefinitionScanner scanner;
    ClassPathBeanDefinitionScanner сканирует указанный пакет на наличие классов, помеченных аннотацией @Component (или ее алиаса). Найденные классы парсируются и для них создаются BeanDefinition. Чтобы было запущено сканирование, в конфигурации должен быть указан пакет для сканирования
    @ComponentScan({"package.name"}).
    AnnotatedBeanDefinitionReader работает в несколько этапов.
    Первый этап – это регистрация всех @Configuration для дальнейшего парсирования. Если в конфигурации используются Conditional, то будут зарегистрированы только те конфигурации,
    для которых Condition вернет true.
    Второй этап – это регистрация BeanDefinitionRegistryPostProcessor, который при помощи класса ConfigurationClassPostProcessor парсирует JavaConfig и создает BeanDefinition.
    Цель первого этапа – это создание всех BeanDefinition. BeanDefinition – это специальный интерфейс, через который можно получить доступ к метаданным будущего бина. В
    зависимости от конфигурации будет использоваться тот или иной механизм парсирования конфигурации.
    BeanDefinition – это объект, который хранит в себе информацию о бине. Сюда входит: из какого класса бин надо создать, scope, установлена ли ленивая инициализация, нужно ли перед данным бином инициализировать другой, init и destroy методы, зависимости. Все полученные BeanDefinition’ы складываются в ConcurrentHashMap, в которой ключом является имя бина, а объектом – сам BeanDefinition. При старте приложения в IoC контейнер попадут бины, которые имеют scope Singleton (устанавливается по- молчанию), остальные создаются тогда, когда они нужны.
    2. Настройка созданных BeanDefinition.

    Есть возможность повлиять на бины до их создания, т. е. получить доступ к метаданным класса. Для этого существует специальный интерфейс BeanFactoryPostProcessor,
    реализовав который получаем доступ к созданным BeanDefinition и можем их изменять. В
    нем один метод.
    Метод postProcessBeanFactory принимает параметром ConfigurableListableBeanFactory.
    Данная фабрика содержит много полезных методов, в том числе getBeanDefinitionNames,
    через который можно получить все BeanDefinitionNames, а уже потом по конкретному имени получить BeanDefinition для дальнейшей обработки метаданных.
    Разберем одну из родных реализаций интерфейса BeanFactoryPostProcessor. Обычно настройки подключения к базе данных выносятся в отдельный property-файл, потом при помощи PropertySourcesPlaceholderConfigurer они загружаются и делается inject этих значений в нужное поле. Так как inject делается по ключу, то до создания экземпляра бина нужно заменить этот ключ на само значение из property-файла. Эта замена происходит в классе, который реализует интерфейс BeanFactoryPostProcessor. Название этого класса –
    PropertySourcesPlaceholderConfigurer. Он должен быть объявлен как static:
    @Bean
    public static PropertySourcesPlaceholderConfigurer configurer() {
    return new PropertySourcesPlaceholderConfigurer();
    }
    3. Создание кастомных FactoryBean.
    FactoryBean – это generic-интерфейс, которому можно делегировать процесс создания бинов определенного типа. Когда конфигурация была исключительно в xml, разработчикам был необходим механизм, с помощью которого они бы могли управлять процессом создания бинов. Именно для этого и был сделан этот интерфейс.
    Создадим фабрику, которая будет отвечать за создание всех бинов типа Color:
    public class ColorFactory implements FactoryBean {
    @Override
    public Color getObject() throws Exception {
    Random random = new Random();
    Color color = new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
    return color;
    }
    @Override
    public Class getObjectType() {
    return Color.class;
    }
    @Override

    public boolean isSingleton() {
    return false;
    }
    }
    Теперь создание бина типа Color.class будет делегироваться ColorFactory, у которого при каждом создании нового бина будет вызываться метод getObject.
    Для тех, кто пользуется JavaConfig, этот интерфейс будет абсолютно бесполезен.
    4. Создание экземпляров бинов.
    Сначала BeanFactory из коллекции Map с объектами BeanDefinition достает те, из которых создает все BeanPostProcessor-ы (инфраструктурные бины), необходимые для настройки обычных бинов.
    Создаются экземпляры бинов через BeanFactory на основе ранее созданных BeanDefinition.
    Созданием экземпляров бинов занимается BeanFactory на основе ранее созданных
    BeanDefinition. Из Map получаем Map.
    Создание бинов может делегироваться кастомным FactoryBean.
    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).
    Прокси – это класс-декорация над бином. Например, можно добавить логику бину, но джава- код уже скомпилирован, поэтому нужно на лету сгенерировать новый класс. Этим классом необходимо заменить оригинальный класс так, чтобы никто не заметил подмены.
    Есть два варианта создания этого класса:

    либо он должен наследоваться от оригинального класса (CGLIB) и переопределять его методы, добавляя нужную логику;

    либо он должен имплементировать те же самые интерфейсы, что и первый класс
    (Dynamic Proxy).
    По конвенции спринга, если какой-то из BeanPostProcessor-ов меняет что-то в классе, то он должен это делать на этапе postProcessAfterInitialization(). Таким образом есть уверенность,
    что initMethod у данного бина работает на оригинальный метод до того, как на него накрутился прокси.
    Хронология событий:
    Сначала сработает метод postProcessBeforeInitialization() всех имеющихся
    BeanPostProcessor-ов.
    Затем, при наличии, будет вызван метод, аннотированный @PostConstruct.
    Если бин имплементирует InitializingBean, то Spring вызовет метод afterPropertiesSet(). Не рекомендуется к использованию как устаревший.
    При наличии будет вызван метод, указанный в параметре initMethod аннотации @Bean.
    В конце бины пройдут через postProcessAfterInitialization(Object bean, String beanName).
    Именно на данном этапе создаются прокси стандартными BeanPostProcessor-ами. Затем отработают кастомные BeanPostProcessor-ы и применят логику к прокси-объектам. После чего все бины окажутся в контейнере, который будет обязательно обновлен методом refresh().
    Но даже после этого можно донастроить бины ApplicationListener-ами.
    Теперь все.
    6. Бины созданы.
    Их можно получить с помощью метода ApplicationContext.getBean().
    7. Закрытие контекста.
    Когда контекст закрывается (метод close() из ApplicationContext), бин уничтожается. Если в бине есть метод, аннотированный @PreDestroy, то перед уничтожением вызовется этот метод.
    Если в аннотации @Bean определен метод destroyMethod, то будет вызван и он.
    Аннотация PostConstruct
    Spring вызывает методы, аннотированные @PostConstruct, только один раз сразу после инициализации свойств компонента. За данную аннотацию отвечает один из
    BeanPostProcessorов.
    Метод, аннотированный @PostConstruct, может иметь любой уровень доступа, может иметь любой тип возвращаемого значения (хотя тип возвращаемого значения игнорируется Spring- ом), метод не должен принимать аргументы. Он также может быть статическим, но преимуществ такого использования метода нет, т. к. доступ у него будет только к статическим полям/методам бина, и в таком случае смысл его использования для настройки бина пропадает.
    Одним из примеров использования @PostConstruct является заполнение базы данных.
    Например, во время разработки может потребоваться создание пользователей по умолчанию.
    Аннотация PreDestroy
    Метод, аннотированный @PreDestroy, запускается только один раз непосредственно перед тем, как Spring удаляет компонент из контекста приложения.

    Как и в случае с @PostConstruct, методы, аннотированные @PreDestroy, могут иметь любой уровень доступа, но не могут быть статическими. Целью этого метода может быть освобождение ресурсов или выполнение любых других задач очистки до уничтожения бина,
    например, закрытие соединения с базой данных.
    Класс, имплементирующий BeanPostProcessor, обязательно должен быть бином, поэтому его помечают аннотацией @Component.
    Расскажите про скоупы бинов? Какой скоуп используется по умолчанию?
    Что изменилось в Spring 5?
    SCOPE_SINGLETON – инициализация произойдет один раз на этапе поднятия контекста.
    SCOPE_PROTOTYPE – инициализация будет выполняться каждый раз по запросу. Причем во втором случае бин будет проходить через все BeanPostProcessor-ы, что может значительно снизить производительность.
    Существует 2 области видимости по умолчанию.
    Singleton – область видимости по умолчанию. В контейнере будет создан только один бин, и все запросы на него будут возвращать один и тот же бин.
    Prototype – приводит к созданию нового бина каждый раз, когда он запрашивается.
    Для бинов со scope «prototype» Spring не вызывает метод destroy(), так как не берет на себя контроль полного жизненного цикла этого бина. Spring не хранит такие бины в своем контексте (контейнере), а отдает их клиенту и больше о них не заботится (в отличие от синглтон-бинов).
    4 области видимости в веб-приложении.
    Request – область видимости – 1 HTTP запрос. На каждый запрос создается новый бин.
    Session – область видимости – 1 сессия. На каждую сессию создается новый бин.
    Application – область видимости – жизненный цикл ServletContext.
    WebSocket – область видимости – жизненный цикл WebSocket.
    Жизненный цикл web csope полный.
    В пятой версии Spring Framework не стало Global session scope. Но появились Application и
    WebSocket.
    Расскажите про аннотацию @ComponentScan
    Первый шаг для описания конфигурации Spring – это добавление аннотаций @Component или наследников.
    Однако Spring должен знать, где искать их. В @ComponentScan указываются пакеты,
    которые должны сканироваться. Можно указать массив строк.
    Spring будет искать бины и в их подпакетах.
    Можно расширить это поведение с помощью параметров includeFilters и excludeFilters в аннотации.
    Для ComponentScan.Filter доступно пять типов фильтров:

    ANNOTATION


    ASSIGNABLE_TYPE

    ASPECTJ

    REGEX

    CUSTOM
    Можно, например, в каком-то ненужном классе в не нашей библиотеке создать для него фильтр, чтобы его бин не инициализировался.
    Как спринг работает с транзакциями? Расскажите про аннотацию
    @Transactional
    Хорошая статья –
    https://www.marcobehler.com/guides/spring-transaction-management- transactional-in-depth
    Коротко:
    Spring создает прокси для всех классов, помеченных @Transactional (либо если любой из методов класса помечен этой аннотацией), что позволяет вводить транзакционную логику до и после вызываемого метода. При вызове такого метода происходит следующее:

    proxy, который создал Spring, создает persistence context (или соединение с базой);

    открывает в нем транзакцию и сохраняет в контексте нити исполнения (в
    ThreadLocal);

    по мере надобности все сохраненное достается и внедряется в бины.
    Таким образом, если в коде есть несколько параллельных нитей, то будет и несколько параллельных транзакций, которые будут взаимодействовать друг с другом согласно уровням изоляции.
    Значения атрибута
    propagation
    у аннотации:
    REQUIRED – применяется по умолчанию. При входе в @Transactional метод будет использована уже существующая транзакция или создана новая транзакция, если никакой еще нет.
    REQUIRES_NEW – новая транзакция всегда создается при входе метод, ранее созданные транзакции приостанавливаются до момента возврата из метода.
    NESTED – корректно работает только с базами данных, которые умеют savepoints. При входе в метод в уже существующей транзакции создается savepoint, который по результатам выполнения метода будет либо сохранен, либо отменен. Все изменения, внесенные методом, подтвердятся только позднее с подтверждением всей транзакции. Если текущей транзакции не существует, будет создана новая.
    MANDATORY – всегда используется существующая транзакция и кидается исключение, если текущей транзакции нет.
    SUPPORTS – метод будет использовать текущую транзакцию, если она есть, либо будет исполнятся без транзакции, если ее нет.
    NOT_SUPPORTED – при входе в метод текущая транзакция, если она есть, будет приостановлена, и метод будет выполняться без транзакции.
    NEVER – явно запрещает исполнение в контексте транзакции. Если при входе в метод будет существовать транзакция, будет выброшено исключение

    Остальные атрибуты:
    rollbackFor = Exception.class – если какой-либо метод выбрасывает указанное исключение,
    контейнер всегда откатывает текущую транзакцию. По умолчанию отлавливает
    RuntimeException.
    noRollbackFor = Exception.class – указание того, что любое исключение, кроме заданного,
    должно приводить к откату транзакции.
    rollbackForClassName и noRollbackForClassName – для задания имен исключений в строковом виде.
    readOnly – разрешает только операции чтения.
    В свойстве transactionManager хранится ссылка на менеджер транзакций, определенный в конфигурации Spring.
    timeOut – по умолчанию используется таймаут, установленный по умолчанию для базовой транзакционной системы. Сообщает менеджеру tx о продолжительности времени, чтобы дождаться простоя tx, прежде чем принять решение об откате не отвечающих транзакций.
    isolation – уровень изолированности транзакций.
    1   ...   17   18   19   20   21   22   23   24   25


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