ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 01.12.2023

Просмотров: 416

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
что 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

Подробно:
Для работы с транзакциями Spring Framework использует AOP-прокси:
Для включения возможности управления транзакциями нужно разместить аннотацию
@EnableTransactionManagement у класса конфигурации @Configuration.
Она означает, что классы, помеченные @Transactional, должны быть обернуты аспектом транзакций. Отвечает за регистрацию необходимых компонентов Spring, таких как
TransactionInterceptor и советы прокси. Регистрируемые компоненты помещают перехватчик в стек вызовов при вызове методов @Transactional. Если используем Spring Boot и имеем зависимости spring-data-* или spring-tx, то управление транзакциями будет включено по умолчанию.
Пропагейшн работает, только если метод вызывает другой метод в другом сервисе. Если метод вызывает другой метод в этом же сервисе, то используется this и вызов проходит мимо прокси. Это ограничение можно обойти при помощи self-injection.
Слой логики (Service) – лучшее место для @Transactional.
Если пометить @Transactional класс @Service, то все его методы станут транзакционными.
Так, при вызове, например, метода save() произойдет примерно следующее:
1. Вначале имеем:

класс TransactionInterceptor, у которого вызывается метод invoke(...), внутри которого вызывается метод класса-родителя
TransactionAspectSupport:
invokeWithinTransaction(...), в рамках которого происходит магия транзакций.

TransactionManager: решает, создавать ли новый EntityManager и/или транзакцию.

EntityManager proxy: EntityManager – это интерфейс, и то, что внедряется в бин в слое
DAO на самом деле не является реализацией EntityManager. В это поле внедряется
EntityManager proxy, который будет перехватывать обращение к полю EntityManager и делегировать выполнение конкретному EntityManager в рантайме. Обычно
EntityManager proxy представлен классом SharedEntityManagerInvocationHandler.

2. Transaction Interceptor.
В TransactionInterceptor отработает код до работы метода save(), в котором будет определено, выполнить ли метод save() в пределах уже существующей транзакции БД или должна стартовать новая отдельная транзакция. TransactionInterceptor сам не содержит логики по принятию решения, решение начать новую транзакцию, если это нужно,
делегируется TransactionManager. Грубо говоря, на данном этапе метод будет обернут в try- catch и будет добавлена логика до его вызова и после:
try {
transaction.begin(); // логика до
service.save();
transaction.commit(); // логика после
} catch(Exception ex) {
transaction.rollback();
throw ex;
}
3. TransactionManager.
Менеджер транзакций должен предоставить ответ на два вопроса:

должен ли создаться новый EntityManager?

должна ли стартовать новая транзакция БД?
Решение принимается, основываясь на следующих фактах:

выполняется ли хоть одна транзакция в текущий момент или нет;

атрибута «propagation» в @Transactional.
Если TransactionManager решил создать новую транзакцию, тогда:

создается новый EntityManager;

EntityManager «привязывается» к текущему потоку (Thread);

«получается» соединение из пула соединений БД;

соединение «привязывается» к текущему потоку.
И EntityManager и соединение привязываются к текущему потоку, используя переменные
ThreadLocal.
4. EntityManager proxy.
Если метод save() слоя Service делает вызов метода save() слоя DAO, внутри которого вызывается, например, entityManager.persist(), то не происходит вызов метода persist()
напрямую у EntityManager, записанного в поле класса DAO. Вместо этого метод вызывает
EntityManager proxy, который достает текущий EntityManager для потока, и у него вызывается метод persist().
5. Отрабатывает DAO-метод save().
6. TransactionInterceptor.


Отработает код после работы метода save(). Другими словами, будет принято решение по коммиту/откату транзакции.
Кроме того, если в рамках одного метода сервиса обращаемся не только к методу save(), а к разным методам Service и DAO, то все они буду работать в рамках одной транзакции,
которая оборачивает данный метод сервиса.
Вся работа происходит через прокси-объекты разных классов. Представим, что у нас в классе сервиса только один метод с аннотацией @Transactional, а остальные нет. Если вызовем метод с @Transactional, из которого вызовем метод без @Transactional, то оба будут отработаны в рамках прокси и будут обернуты в нашу транзакционную логику. Однако, если вызовем метод без @Transactional, из которого вызовем метод с @Transactional, то они уже не будут работать в рамках прокси и не будут обернуты в транзакционную логику.
Что произойдет, если один метод с @Transactional вызовет другой метод с
@Transactional?
Если это происходит в рамках одного сервиса, то второй транзакционный метод будет считаться частью первого, так как вызван у него изнутри, а так как спринг не знает о внутреннем вызове, то не создаст прокси для второго метода.
Что произойдет, если один метод БЕЗ @Transactional вызовет другой
метод с @Transactional?
Так как Spring не знает о внутреннем вызове, то не создаст прокси для второго метода.
Будет ли транзакция отменена, если будет брошено исключение, которое
указано в контракте метода?
Если в контракте описано это исключение, то она не откатится. Unchecked-исключения в транзакционном методе можно ловить, а можно и не ловить.
Расскажите про аннотации @Controller и @RestController. Чем они
отличаются? Как вернуть ответ со своим статусом (например 213)?
@Controller – специальный тип класса, обрабатывает HTTP-запросы и часто используется с аннотацией @RequestMapping.
@RestController ставится на класс-контроллер вместо @Controller. Она указывает, что этот класс оперирует не моделями, а данными. Она состоит из аннотаций @Controller и
@ResponseBody. Была введена в Spring 4.0 для упрощения создания RESTful веб-сервисов.
@ResponseBody сообщает контроллеру, что возвращаемый объект автоматически сериализуется (используя Jackson message converter) в json или xml и передается обратно в объект HttpResponse.
ResponseEntity используется для формирования кастомизированного HTTP-ответа с пользовательскими параметрами (заголовки, код статуса и тело ответа). Во всех остальных случаях достаточно использовать @ResponseBody.
Если хотим использовать ResponseEntity, то должны вернуть его из метода, Spring позаботится обо всем остальном.
return ResponseEntity.status(213);