Сначала вспомним часто используемые аннотации AOP:
Порядок выполнения AOP в Spring 4 при нормальном выполнении и при возникновении исключения
try {
@Before
method.invoke(obj, args);
@AfterReturning
} catch () {
@AfterThrowing
} finally {
@After
}
Нормальное выполнение: @Before(предварительное уведомление) => @After(последующее уведомление) => @AfterReturning(уведомление после возврата)
Выполнение при исключении: @Before(предварительное уведомление) => @After(последующее уведомление) => @AfterThrowing(уведомление при исключении)
Если в конфигурации также задействовано обертывающее оповещение (around advice), то выполнение его предварительной обработки происходит до выполнения @Before.
Предварительная обработка обертывающего оповещения также выполняется до @After, @AfterReturning и @AfterThrowing.
Обычный результат:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
вызов метода invokeMethod()
постобработка обертывающего оповещения
@After постоповещение
@AfterReturning / @AfterThrowing
```**Аномальный результат:**
```java
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@After постоповещение
@AfterReturning / @AfterThrowing
Порядок выполнения AOP в Spring 5
обычное выполнение: @Before(предварительное оповещение) => @AfterReturning(обычное завершение) => @After(постоповещение)
анномальное выполнение: @Before(предварительное оповещение) => @AfterThrowing(исключение метода) => @After(постоповещение)
Обычное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
постобработка обертывающего оповещения
@After постоповещение
Аномальное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@AfterReturning / @AfterThrowing
@After
Порядок выполнения AOP в Spring 5
обработка успешного выполнения с использованием оборачивающего советника:
```java
предварительная обработка оборачивания
@Before предварительный советник
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
@After последующий советник
последняя обработка оборачивания
обработка ошибочного выполнения с использованием оборачивающего советника:
предварительная обработка оборачивания
@Before предварительный советник
@AfterReturning / @AfterThrowing
@After
Аномальный результат:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@After постоповещение
@AfterReturning / @AfterThrowing
Порядок выполнения AOP в Spring 5
обычное выполнение: @Before(предварительное оповещение) => @AfterReturning(обычное завершение) => @After(постоповещение)
анномальное выполнение: @Before(предварительное оповещение) => @AfterThrowing(исключение метода) => @After(постоповещение)
Обычное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
постобработка обертывающего оповещения
@After постоповещение
Аномальное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@AfterReturning / @AfterThrowing
@After
Порядок выполнения AOP в Spring 5
обработка успешного выполнения с использованием оборачивающего советника:
```java
предварительная обработка оборачивания
@Before предварительный советник
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
@After последующий советник
последняя обработка оборачивания
обработка ошибочного выполнения с использованием оборачивающего советника:
предварительная обработка оборачивания
@Before предварительный советник
@AfterReturning / @AfterThrowing
@After
Аномальный результат:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@After постоповещение
@AfterReturning / @AfterThrowing
Порядок выполнения AOP в Spring 5
обычное выполнение: @Before(предварительное оповещение) => @AfterReturning(обычное завершение) => @After(постоповещение)
анномальное выполнение: @Before(предварительное оповещение) => @AfterThrowing(исключение метода) => @After(постоповещение)
Обычное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
постобработка обертывающего оповещения
@After постоповещение
Аномальное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@AfterReturning / @AfterThrowing
@After
Порядок выполнения AOP в Spring 5
обработка успешного выполнения с использованием оборачивающего советника:
```java
предварительная обработка оборачивания
@Before предварительный советник
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
@After последующий советник
последняя обработка оборачивания
обработка ошибочного выполнения с использованием оборачивающего советника:
предварительная обработка оборачивания
@Before предварительный советник
@AfterReturning / @AfterThrowing
@After
Аномальный результат:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@After постоповещение
@AfterReturning / @AfterThrowing
Порядок выполнения AOP в Spring 5
обычное выполнение: @Before(предварительное оповещение) => @AfterReturning(обычное завершение) => @After(постоповещение)
анномальное выполнение: @Before(предварительное оповещение) => @AfterThrowing(исключение метода) => @After(постоповещение)
Обычное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
постобработка обертывающего оповещения
@After постоповещение
Аномальное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@AfterReturning / @AfterThrowing
@After
Порядок выполнения AOP в Spring 5
обработка успешного выполнения с использованием оборачивающего советника:
```java
предварительная обработка оборачивания
@Before предварительный советник
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
@After последующий советник
последняя обработка оборачивания
обработка ошибочного выполнения с использованием оборачивающего советника:
предварительная обработка оборачивания
@Before предварительный советник
@AfterReturning / @AfterThrowing
@After
Аномальный результат:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@After постоповещение
@AfterReturning / @AfterThrowing
Порядок выполнения AOP в Spring 5
обычное выполнение: @Before(предварительное оповещение) => @AfterReturning(обычное завершение) => @After(постоповещение)
анномальное выполнение: @Before(предварительное оповещение) => @AfterThrowing(исключение метода) => @After(постоповещение)
Обычное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
постобработка обертывающего оповещения
@After постоповещение
Аномальное выполнение с учетом обертывающего оповещения:
предварительная обработка обертывающего оповещения
@Before предварительное оповещение
@AfterReturning / @AfterThrowing
@After
Порядок выполнения AOP в Spring 5
обработка успешного выполнения с использованием оборачивающего советника:
```java
предварительная обработка оборачивания
@Before предварительный советник
вызов метода invokeMethod()
@AfterReturning / @AfterThrowing
@After последующий советник
последняя обработка оборачивания
обработка ошибочного выполнения с использованием оборачивающего советника:
предварительная обработка оборачивания
@Before предварительный советник
@AfterReturning / @AfterThrowing
@After
```## 3. Циклическая зависимость в Spring
[Циклическая зависимость](https://www.cnblogs.com/chenpt/p/9896618.html)
### 1) Концепция циклической зависимости
Циклическая зависимость -> циклическое использование. --> Это когда два или более бинов взаимно зависят друг от друга, создавая замкнутый цикл.
Пример: A зависит от B, B зависит от C, а C зависит от A. [Обратите внимание: это не циклический вызов функции [это бесконечный цикл, если нет условий для завершения], это взаимная зависимость объектов.]
.jpg)
### 2) **Две формы циклической зависимости в контейнере Spring**
(1) Циклическая зависимость через конструктор
(2) Циклическая зависимость через setter (setter-зависимость).
### 3) **Обработка циклической зависимости в Spring**
**(1) Циклическая зависимость через конструктор (невозможно решить)**Это циклическая зависимость, созданная через конструкторы. Такая зависимость не имеет решения, и она приводит к выбросу исключения (BeanCreationException).
Контейнер Spring помещает каждый идентификатор bean, который создается, в "текущую корзину создания bean", и идентификатор bean остается в этой корзине до завершения его создания. Если во время создания bean обнаруживается, что он уже находится в корзине, выбрасывается исключение BeanCurrentlyInCreationException, указывающее на циклическую зависимость; для завершенных bean идентификатор bean удаляется из "текущей корзины создания bean".
**(2) Циклическая зависимость через setter (решаемая)**Это циклическая зависимость, созданная через setter.
Решение: Контейнер Spring предварительно выдает bean, который был создан через конструктор, но ещё не завершил другие шаги (например, setter-внедрение). Это решение применимо только для singleton scope bean. Через предварительное выведение singleton-фабрики, другие bean могут ссылаться на этот bean.
**(3) Обработка циклической зависимости для prototype scope bean (невозможно решить)**
Для bean с prototype scope контейнер Spring не может завершить внедрение зависимостей, так как контейнер Spring не кэширует bean с prototype scope, поэтому он не может предварительно вывести bean, который ещё создаётся.
```### 4) **Анализ области (scope)**
beanFactory выполняет не только обязанности IoC, но также управляет жизненным циклом объектов.
Scope используется для объявления сценариев, в которых должны существовать объекты в контейнере, или времени их жизни. То есть контейнер создает и собирает объекты до того, как они попадут в свой scope, а после того, как объект больше не находится в этом scope, контейнер обычно уничтожает эти объекты.
### 5) Какие типы scope предоставляются контейнером Spring?- singleton: В контейнере Spring существует только один экземпляр, все объекты будут использовать этот единственный экземпляр. (Примечание: не путайте с паттерном Singleton)
- prototype: Каждый раз, когда контейнер получает запрос, он создает новый экземпляр объекта.
- request (используется только в веб-приложениях): Для каждого HTTP-запроса создается новый объект request-processor для текущего запроса, и после завершения запроса, жизнь этого объекта заканчивается.
- session (используется только в веб-приложениях): Для каждого отдельного сессионного контекста создается новый экземпляр объекта UserPreference.
- global session (используется только в веб-приложениях): Этот тип scope имеет смысл только при использовании портлетов в веб-приложениях. Он отображает глобальный scope сессии портлета. Если этот тип scope используется в обычном веб-приложении на основе servlet, контейнер будет рассматривать его как обычный scope сессии.## 4. Как определить наличие циклической зависимости?
Определение циклической зависимости довольно просто. При создании Bean его можно пометить, и если во время рекурсивного вызова обнаруживается, что Bean уже создается, это указывает на циклическую зависимость.
## 5. Как Spring решает проблему циклической зависимости?
**Spring использует тройное кэширование для решения проблемы циклической зависимости**
Теоретическая основа решения проблемы циклической зависимости в Spring базируется на передаче ссылок в Java. Когда мы получаем ссылку на объект, поля или свойства объекта могут быть заполнены позже (но конструктор должен быть вызван до получения ссылки).
Инициализация singleton-объекта в Spring состоит из трех шагов:
(1) createBeanInstance: Инстанцирование, то есть вызов конструктора объекта для его инстанцирования.
(2) populateBean: Заполнение свойств, этот шаг включает заполнение зависимостей объекта.
(3) initializeBean: Вызов метода init из XML конфигурации Spring.Из вышеописанных шагов инициализации singleton-объекта можно понять, что циклическая зависимость обычно возникает на этапах (1) и (2). То есть на этапах конструкторской циклической зависимости и циклической зависимости полей. Чтобы решить проблему циклических зависимостей, следует обратиться к процессу инициализации. Для синглтона существует всего один объект в течение всего жизненного цикла контейнера Spring, поэтому логично предположить, что этот объект должен храниться в кэше. Чтобы решить проблему циклической зависимости синглтонов, Spring использует три уровня кэширования.Давайте рассмотрим исходный код. Три уровня кэширования включают:
```java
/** Кэш синглтон-объектов: имя бина --> экземпляр бина */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Кэш синглтон-фабрик: имя бина --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Кэш ранних синглтон-объектов: имя бина --> экземпляр бина */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
Эти три уровня кэширования представляют собой:
singletonFactories: кэш синглтон-фабрик earlySingletonObjects: кэш ранних синглтон-объектов singletonObjects: кэш синглтон-объектов
Три уровня кэширования в Spring
При запуске Spring используются три карты, известные как три уровня кэширования.
Процесс запуска Spring включает следующие шаги:
beanFactory
и загрузка конфигурационных файловbeanDefinition
, получение всех свойств, зависимостей и необходимых обработчиков для инициализации биновbeanFactory
-контейнера и инициализация всех синглтон-биновapplicationContext
При использовании этого механизма рекомендуется использовать DI или внедрение зависимостей. Мы можем внедрять нужные нам классы в нужные места, используя различные способы внедрения: конструкторное внедрение, внедрение через get/set методы и аннотации. Сейчас мы чаще всего используем аннотации @Autowired
или @Resource
. Затем следует программирование с использованием аспектов (AOP), которое позволяет улучшить функциональность кода без изменения исходного кода. Мы конфигурируем точки среза в конфигурационных файлах, а затем реализуем логику аспекта для усиления кода. Усиление кода может включать улучшение логики до выполнения среза, во время выполнения и после выполнения. Это позволяет не менять исходный код. В наших проектах это обычно используется для проверки прав доступа, логирования и управления транзакциями.
Зависимый объект передается через параметры конструктора и внедряется в объект, требующий этой зависимости, при инициализации объекта. Преимущества: После инициализации объекта он становится доступным для использования. Недостатки: Если требуется внедрить много объектов, параметры конструктора могут стать слишком длинными; Не очень гибкий. Если есть несколько способов внедрения, каждый из которых требует внедрения только нескольких зависимостей, придется создать несколько перегруженных конструкторов, что усложняет процесс.
IoC-сервис провайдер внедряет зависимые объекты в зависимости путем вызова предоставленных сеттеров для членских переменных. Преимущества: Гибкость. Можно выборочно внедрять нужные объекты. Недостатки: После завершения инициализации зависимых объектов, но до внедрения зависимостей, последние еще не доступны для использования.
Преимущества: Имена интерфейсов и функций не имеют значения, важно лишь то, что аргумент функции представляет тип внедряемого объекта. Недостатки: Слишком инвазивно, не рекомендуется к использованию. Примечание: Что такое инвазивность? Если класс A использует функцию, предоставленную другим классом, и для использования этой функции требуется добавить дополнительный код в свой класс, это и есть инвазивность.## 9. Как настроить переадресацию и перенаправление в Spring MVC?
(1) Перенаправление: добавьте forward:
перед значением возврата, например "forward:user.do?name=method4"
.
(2) Переадресация: добавьте redirect:
перед значением возврата, например "redirect:http://www.baidu.com"
.
Сначала рассмотрим жизненный цикл сервлета: создание экземпляра, инициализация, обслуживание запросов, завершение работы. Жизненный цикл бинов в контексте Spring также аналогичен, как показано ниже:
Бины в контексте Spring могут быть разделены на пять областей действия:(1) singleton: По умолчанию, в каждом контексте существует только один экземпляр бина, управляемый BeanFactory. (2) prototype: Для каждого запроса бина предоставляется отдельный экземпляр. (3) request: Для каждого сетевого запроса создаётся отдельный экземпляр; после завершения запроса бин становится недействительным и подлежит сборке мусора. (4) session: Аналогично области действия request, но гарантирует наличие одного экземпляра бина для каждой сессии; после истечения срока действия сессии, бин становится недействительным. (5) global-session: Глобальная область действия, глобальная сессия связана с приложениями Portlet. Когда ваше приложение работает в контейнере Portlet, оно может содержать множество Portlet. Если вы хотите объявить общие глобальные переменные для всех Portlet, эти переменные должны храниться в глобальной сессии. Глобальная область действия аналогична области действия сессии в сервлетах.## 12. Какие паттерны проектирования используются в фреймворке Spring?
(1) Фабричный метод: BeanFactory представляет собой реализацию простого фабричного метода, используемую для создания экземпляров объектов;
(2) Одиночка: Базовый режим Beans — это одиночный паттерн;
(3) Прокси: Функциональность AOP в Spring использует динамическое проксирование JDK и технологию генерации байт-кодов CGLIB;
(4) Шаблонный метод: используется для решения проблемы повторяющегося кода. Например, RestTemplate, JmsTemplate, JpaTemplate.
(5) Наблюдатель: Определяет отношение "один ко многим" между объектами, при котором когда состояние одного объекта изменяется, все зависящие от него объекты получают уведомление и автоматически обновляются. Например, реализация слушателей в Spring — ApplicationListener.
При работе с Spring Boot можно использовать встроенные утилиты для автоматического конфигурирования приложения. Например, spring-boot-devtools
предоставляет удобные инструменты для разработки, такие как автообновление приложения при сохранении изменений в коде.
spring-boot-devtools
— это набор утилит, который помогает упростить процесс разработки. Он включает в себя следующие возможности:
Для использования spring-boot-devtools
, необходимо добавить его в список зависимостей вашего проекта. Это можно сделать, добавив следующую строку в файл pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
Также можно использовать spring-boot-maven-plugin
для управления жизненным циклом сборки:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
Пример использования spring-boot-devtools
может выглядеть следующим образом:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Этот пример демонстрирует базовую конфигурацию приложения с использованием spring-boot-devtools
.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )