1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/yaoyunpeng-java_senior_development_engineer_interview_notes

Клонировать/Скачать
part5-spring机制.txt 25 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 08.06.2025 19:58 b8b6f40
1. OOP: объектно-ориентированное программирование
# Пояснение: OOP вводит концепции инкапсуляции, наследования и полиморфизма для создания иерархии объектов, которая моделирует набор общих действий.
2. AOP: аспектно-ориентированное программирование
# Пояснение: AOP основывается на концепции IoC и является полезным дополнением к OOP. OOP позволяет вам определить вертикальные зависимости, но не горизонтальные.
## Проще говоря, это те логические или ответственности, которые не связаны с бизнесом, но используются несколькими модулями бизнеса. Это помогает уменьшить повторяющийся код в системе, уменьшить связь между модулями и улучшить будущую оперируемость и поддерживаемость.
# Принцип: реализуется с использованием паттерна прокси. Перед вызовом целевого метода вызывается метод прокси, а затем прокси возвращает результат вызова. В Spring AOP используется динамическое прокси.
# Основные концепции:
# Аспект: универсальные бизнес-логические коды, рассеянные по всему системе, такие как модуль логирования, модуль прав доступа, модуль транзакций и т. д. Аспект используется для загрузки точек среза и советов.
# Совет: совет представляет собой код, который будет выполнен после перехвата точки соединения. Советы делятся на пять типов: до, после, вокруг, ошибки и finally.
# Точка соединения: точка, которая была перехвачена.Поскольку Spring поддерживает только методы как точки соединения, в Spring точка соединения представляет собой перехваченный метод. Однако точки соединения могут быть также полями или конструкторами.
# Точка среза: перехваченный метод, который становится точкой среза после перехвата.
# Целевой объект: целевой объект прокси, который представляет собой модуль, в который нужно вплести аспекты, такие как модуль 1, 2 и 3.
# Вплетание: процесс применения аспекта к целевому объекту через точку среза и создание прокси-объекта.
# Прокси AOP: объект, созданный AOP-фреймворком, содержащий советы. В Spring прокси AOP может быть динамическим прокси JDK или CGLIB.
# Пример: если модули 1, 2 и 3 требуют записи логов, то если логика записи логов будет написана в каждом модуле, то возникнут две проблемы:
# 1. нарушение инкапсуляции модуля
# 2. большое количество повторяющегося кода
# Проблема повторяющегося кода может быть решена путем упаковки логики записи логов в класс, а затем использование этого класса для записи логов в местах, где это необходимо. Однако это не решает проблему нарушения инкапсуляции модуля.
# AOP может решить эту проблему, используя аспекты, динамически вплетая их в модули (на самом деле это управление объектами модулей с помощью прокси), таким образом решая проблему повторяющегося кода и не нарушая инкапсуляции модуля.
3.IOC: инверсия управления# Описание: Используется для снижения耦合度,将所有的bean交由spring管理,其依赖的原理是依赖注入(Dependency Injection,简称DI)
# Преимущества: Уменьшение耦合度, реализация принципа открытия и закрытия
# Реализация:
- Чтение аннотаций или конфигурационных файлов для получения необходимых сервисов, получение имени класса
- Использование рефлексии для создания экземпляра объекта на основе имени класса
- Передача экземпляра объекта через конструктор или setter вызывающему коду4. Транзакции
- # Описание: Суть транзакций Spring заключается в поддержке транзакций базой данных. Без поддержки транзакций базой данных, Spring не может предоставить функциональность транзакций. Для чистых операций JDBC с базой данных, чтобы использовать транзакции, можно выполнить следующие шаги:
- ## Получение соединения Connection con = DriverManager.getConnection()
- ## Открытие транзакции con.setAutoCommit(true/false);
- ## Выполнение операций CRUD
- ## Подтверждение или откат транзакции con.commit() / con.rollback();
- ## Закрытие соединения conn.close();
- ## После использования функциональности управления транзакциями Spring, нам больше не нужно писать код для шагов OnClickListener 2 и 4, так как это делает Spring автоматически. Как Spring открывает транзакции перед CRUD и закрывает их после? Решение этой проблемы позволит нам понять принцип реализации управления транзакциями Spring в целом. Ниже приведен краткий обзор, используя аннотации в качестве примера:
- ## Включение аннотаций в конфигурационном файле, использование аннотации @Transactional для маркировки соответствующих классов и методов - ## При запуске Spring анализирует и создает соответствующие бины, проверяет классы и методы с соответствующими аннотациями и создает для них прокси, а также внедряет соответствующие параметры @Transaction, что позволяет прокси автоматически управлять транзакциями (открытие, подтверждение или откат транзакций при возникновении ошибок).
- ## Реальные транзакции базы данных подтверждаются или откатываются с помощью binlog или redo log.
- # Механизм транзакций Spring включает декларативные и программные транзакции. Здесь акцент делается на декларативных транзакциях, программные транзакции не получают широкого использования в реальном мире, но могут быть полезны для изучения и обучения.
- # Декларативные транзакции: декларативные транзакции Spring позволяют нам избавиться от сложных операций управления транзакциями, таких как получение соединения, его закрытие, подтверждение или откат транзакций. Мы больше не должны писать большое количество кода try...catch...finally в методах, связанных с транзакциями.
- ## При использовании декларативных транзакций Spring важным понятием является атрибут транзакции. Свойства транзакции обычно включают в себя поведение распространения транзакции, уровень изоляции транзакции, время ожидания транзакции, флаг только-чтения транзакции.При разбиении транзакций нам нужно определить свойства транзакций, то есть настроить их атрибуты.# Поведение распространения транзакции (7 типов):
#PROPAGATION_REQUIRED: поддерживает текущую транзакцию, если текущей транзакции нет, создает новую. Это самый распространенный выбор и по умолчанию используется в Spring.
#PROPAGATION_REQUIRES_NEW: создает новую транзакцию, если текущая транзакция существует, она приостанавливается. Новая транзакция никак не связана с приостановленной, они являются независимыми транзакциями. Если внешняя транзакция неудачна и откатывается, внутренняя транзакция не будет откатываться. Если внутренняя транзакция неудачна и выбрасывает исключение, внешняя транзакция может его перехватить и не выполнить откат.
#PROPAGATION_SUPPORTS: поддерживает текущую транзакцию, если текущей транзакции нет, выполняется без транзакции.
#PROPAGATION_MANDATORY: поддерживает текущую транзакцию, если текущей транзакции нет, выбрасывает исключение.
#PROPAGATION_NOT_SUPPORTED: выполняется без транзакции, если текущая транзакция существует, она приостанавливается.
#PROPAGATION_NEVER: выполняется без транзакции, если текущая транзакция существует, выбрасывает исключение.
#PROPAGATION_NESTED: если активная транзакция существует, выполняется в вложенной транзакции. Если активной транзакции нет, выполняется как PROPAGATION_REQUIRED. Она использует отдельную транзакцию с несколькими точками отката. Откат внутренней транзакции не влияет на внешнюю транзакцию.Эта опция работает только с менеджером транзакций DataSourceTransactionManager.# Уровень изоляции
#ISOLATION_DEFAULT: это по умолчанию уровень изоляции PlatformTransactionManager, использует уровень изоляции транзакции по умолчанию базы данных.
#Далее четыре уровня изоляции соответствуют уровням изоляции JDBC.
#ISOLATION_READ_UNCOMMITTED: это самый низкий уровень изоляции транзакции, он позволяет другой транзакции видеть неотправленные данные текущей транзакции. Этот уровень изоляции может привести к грязным чтениям, неповторным чтениям и иллюзорным чтениям.
#ISOLATION_READ_COMMITTED: гарантирует, что данные, измененные одной транзакцией, будут видны другой транзакции только после их подтверждения. Другая транзакция не может видеть неотправленные данные.
#ISOLATION_REPEATABLE_READ: этот уровень изоляции транзакции предотвращает грязные чтения и неповторные чтения. Однако он может привести к иллюзорным чтениям.
#ISOLATION_SERIALIZABLE: это самый дорогой по затратам, но самый надежный уровень изоляции транзакции. Транзакции обрабатываются как последовательные.# Вложенные транзакции
# Предположим, что внешняя транзакция Service A метод A() вызывает внутреннюю Service B метод B().
# PROPAGATION_REQUIRED (по умолчанию в Spring): если уровень транзакции для ServiceB.methodB() определен как PROPAGATION_REQUIRED, то при выполнении ServiceA.methodA() Spring уже инициирует транзакцию.
## При вызове ServiceB.methodB() этот метод видит, что он уже находится внутри транзакции ServiceA.methodA(),
## и не инициирует новую транзакцию. Если ServiceB.methodB() обнаруживает, что он не находится внутри транзакции, он инициирует новую. Таким образом, если возникает исключение в ServiceA.methodA() или в ServiceB.methodB(), транзакция будет откатываться.
# PROPAGATION_REQUIRES_NEW: например, если уровень транзакции для ServiceA.methodA() определен как PROPAGATION_REQUIRED, а для ServiceB.methodB() — как PROPAGATION_REQUIRES_NEW, то при выполнении ServiceB.methodB() транзакция ServiceA.methodA() будет приостановлена,
## и ServiceB.methodB() инициирует новую транзакцию. После завершения транзакции ServiceB.methodB() она продолжит выполнение. Отличие от PROPAGATION_REQUIRED заключается в том, что если ServiceB.methodB() завершит свою транзакцию, то при откате ServiceA.methodA() транзакция ServiceB.methodB() не будет откатываться. Если ServiceB.methodB() завершит свою транзакцию, но при этом возникнет исключение, то если это исключение будет перехвачено ServiceA.methodA(), транзакция ServiceA.methodA() может быть завершена (в зависимости от типа исключения).
# PROPAGATION_SUPPORTS: если уровень транзакции для ServiceB.methodB() определен как PROPAGATION_SUPPORTS. В этом случае, если при выполнении ServiceB.methodB() обнаруживается, что ServiceA.methodA() уже инициировал транзакцию, то ServiceB.methodB() присоединяется к этой транзакции. Если ServiceA.methodA() не инициировал транзакцию, то ServiceB.methodB() также не инициирует транзакцию. В этом случае транзакционность внутренних методов полностью зависит от внешней транзакции.
#PROPAGATION_NESTED: в этом случае ситуация становится более сложной, если свойство транзакции для ServiceB.methodB() определено как PROPAGATION_NESTED. В этом случае ServiceB.methodB() может откатиться до точки сохранения (SavePoint), созданной перед началом выполнения этого метода. Если ServiceB.methodB() выбрасывает исключение, то внутренняя транзакция (ServiceB.methodB()) будет откатываться до точки сохранения, а внешняя транзакция (ServiceA.methodA()) может обрабатывать это исключение следующими способами:
#перехват исключения и выполнение логики обработки исключения, это наиболее ценное свойство вложенной транзакции, так как она позволяет выполнять ветвление. Если ServiceB.methodB() завершается неудачно, то выполняется ServiceC.methodC(), а ServiceB.метод B был откатан до точки сохранения, которая была до его выполнения, поэтому он не создаёт грязных данных (аналогично тому, как будто этот метод никогда не выполнялся).Эта особенность может быть использована в некоторых специфических бизнес-процессах, в то время как PROPAGATION_REQUIRED и PROPAGATION_REQUIRES_NEW не могут этого сделать.
```java
void methodA() {
try {
ServiceB.methodB();
} catch (SomeException) {
// выполнение других бизнес-процессов, например ServiceC.methodC();
}
}
```
# внешний транзактный откат/коммит код не изменяется, поэтому если внутренний транзакт (ServiceB#methodB) откатывается, то сначала ServiceB.methodB откатывается до точки сохранения, которая была до его выполнения (это происходит в любом случае), внешний транзакт (т. е. ServiceA#methodA) будет решать, коммитировать или откатывать, в зависимости от конкретной конфигурации
# три других типа транзактных свойств практически не используются, поэтому их анализ не проводится
5. работа механизма Spring MVC
Первый шаг: пользователь отправляет запрос к фронт-контроллеру (DispatcherServlet)
Второй шаг: фронт-контроллер обращается к мапперу обработчиков (HandlerMapping) для поиска обработчика (Handler): поиск осуществляется через конфигурацию XML или аннотации
Третий шаг: после поиска маппер обработчиков (HandlerMapping) возвращает цепочку выполнения (HandlerExecutionChain) фронт-контроллеру
Четвёртый шаг: фронт-контроллер (DispatcherServlet) вызывает адаптер обработчика (HandlerAdapter) для выполнения обработчика (Handler)
Пятый шаг: адаптер обработчика вызывает обработчикШестой шаг: обработчик завершает выполнение и возвращает ModelAndView адаптеру обработчика.
Седьмой шаг: адаптер обработчика возвращает ModelAndView фронт-контроллеру.
Восьмой шаг: фронт-контроллер обращается к мапперу представлений (ViewResolver) для разбора представления.
Девятый шаг: маппер представлений возвращает View фронт-контроллеру.
Десятый шаг: фронт-контроллер рендерит представление.
Одиннадцатый шаг: фронт-контроллер отвечает пользователю результатом.
6. Принцип работы пула подключений и его виды
# HikariCP: Hikari по-японски означает "свет", предшественником является BoneCP, BoneCP в 2013 году перестал обновляться
# Druid: функциональность довольно полная, и имеет хорошую расширяемость, удобно для мониторинга и отслеживания JDBC-интерфейсов
# dbcp: это проект Java-пула подключений от Apache, также используется как компонент пула подключений в Tomcat
# tomcat-jdbc: также продукт от Apache, в Tomcat 7.0 используется для замены dbcp, так как dbcp является однопоточным, и в условиях высокой конкуренции производительность ухудшается, подробнее см. официальную документацию: https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#Introduction
# c3p0: в условиях высокой конкуренции производительность очень низкая, слишком старый, код очень сложный, что затрудняет поддержку. Не рекомендуется к использованию
# Сравнительный анализ:
#1: С точки зрения производительности hikariCP>druid>tomcat-jdbc>dbcp>c3p0.Высокая производительность HikariCP обусловлена минимальным количеством конкуренции за блокировку.
#2: Druid обладает наиболее полным функционалом, включая возможность перехвата SQL-запросов, а также предоставляет более полные статистические данные и имеет хорошую масштабируемость.
#3: В целом, с точки зрения производительности и масштабируемости, можно рассмотреть использование Druid или HikariCP как пула подключений.
#4: Можно включить кэширование prepareStatement, что повысит производительность примерно на 20%.
#Сравнение производительности: http://freeman1.iteye.com/blog/2268874
7, используемые в Spring паттерны проектирования
#Паттерн Singleton: например, при создании bean
#Паттерн Фабрики: это очевидно, используется во всех BeanFactory и ApplicationContext
#Паттерн Прокси: используется в реализации AOP с помощью динамического прокси JDK
#Паттерн Шаблон Метода: JdbcTemplate в Spring
#Паттерн Стратегии: в реализации AOP используются два разных подхода, динамическое прокси JDK и CGLIB
#Паттерн Наблюдателя: например, ApplicationListener

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/yaoyunpeng-java_senior_development_engineer_interview_notes.git
git@api.gitlife.ru:oschina-mirror/yaoyunpeng-java_senior_development_engineer_interview_notes.git
oschina-mirror
yaoyunpeng-java_senior_development_engineer_interview_notes
yaoyunpeng-java_senior_development_engineer_interview_notes
master