Skip to content
Gallery
Theory for java developer
Share
Explore
Java

icon picker
Spring Boot

Фреймворк - это внешний каркас, предоставляющий заранее определенные точки расширения. В эти точки расширения вы и вставляете свой код, но когда он будет вызван определяет именно фреймворк. Создавать объекты классов и вызывать методы за нас будет уже сам фреймворк.
image.png

Spring - общее названия для целого ряда небольших фреймворков, каждый из которых выполняет свою работу. Как видно, у спринга модульная структура. Это позволяет подключать только те модули, что нам нужны для нашего приложения и не подключать те, которыми мы заведомо не будем пользоваться. Именно этот подход и помог спрингу обойти своего конкурента в то время (EJB).
Dependency Inversion(DI) - инверсию зависимостей, то есть попытки не делать жестких связей между вашими модулями/классами, где один класс напрямую завязан на другой (SOLID - D):
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Принцип который говорит о том что сущность не сама создает свои зависимости, они подставляются из вне, а DI(ниже) это частный случай.
Inversion of Control (IoC) — инверсия управления, при использовании библиотеки вы сами прописываете в своем коде какой метод какого объекта вызвать, а в случае с фреймворками уже фреймворк будет вызывать в нужный ему момент тот код, который вы написали. Фреймворк управляете процессом выполнения программы за вас. Вы передали ему управление (инверсия управления).
Dependency Injection(DI) — внедрение зависимостей, специальный паттерн, который уменьшает связь между компонентами. При применении DI, ваш код становится легче понимать и тестировать. Согласно паттерну DI, создание объектов для зависимостей переходит на фабрику или отдается третьей стороне. Это означает, что мы можем сосредоточиться на использовании этих объектов вместо их создания.
Это когда объекты создаются не вы в main-е и потом передаются в методы своих объектов, а за вас их внедряет спринг(если они помечены аннотацией), а вы ему просто говорите что-то типа "хочу сюда получить тот объект" и он вам его передает в ваш метод.
ApplicationContext или как сделать свой IoC - это набор бинов (объектов), реализация простая:
У нас есть куча классов с кучей методов, где иногда нам нужен для метода котик, а для другого метода — собачка, а в каких-то методах — все два.
Да, мы можем в main-е сначала создать эти два объекта, а потом их передавать в наши классы, а уже внутри классов — в нужные нам методы... И так по всей программе. Сложно, не красиво. Тогда мы решаем хранить мапу, где ключ - имя нужного нам объекта, а значением — сам объект.
Мы сможем доставать нужные нам объекты по их имени: get("попугайчик") и в ответ получили объект попугайчика. Или ключ — это класс объекта, а значение — сам объект, тогда мы сможем указать уже не имя объекта, а просто класс нужного нам объекта, тоже удобно.
Написать обертку над мапой, чтобы в каких-то случаях доставать объекты по их имени, а в других случаях — по классу.
Написать специальные аннотации чтобы они автоматически подтягивали по имени поля объект из map. И мы каждый раз не обращались к мапе и не тащили ее через все объекты.
Мы переложили ответственность за создание объектов, передачу их в методы - спрингу (IoC).
Bean - это объект класса который может храниться в ApplicationContext и связываться(подставляться) в нужное место при его внедрении. В Spring-е бином (bean) называют любой класс, который управляется контейнером Spring. То есть такими вещами, как создание экземпляра бина, его инициализация, внедрение зависимостей и параметров, деинициализация, генерация всевозможных оберток над бином, занимается не наш код, а IoC-контейнер Spring.

Proxy

image.png
Тут не вызовется @Transactional по тому что нет Proxy т.к. создается в том же классе: 1) Переместить метод createAccount(Account acc) в другой класс. 2) использовать селф инициализацию

Bean Scope - 6

singleton - создается один раз инжектится один и тот же бин.
prototype - при каждом запросе создает новый.
-----------Web Scope----------
request - создает экземпляр бина для одного HTTP-запроса.
session - создает экземпляр бина для HTTP-сессии.
application - Это похоже на область видимости singleton, но есть очень важное отличие в области видимости. Тот же экземпляр бина используется в нескольких приложениях на основе сервлетов, работающих в одном и том же контексте сервлета, в то время как бины с областью видимости singleton ограничены только одним контекстом приложения.
websocket - Создается один раз и виден во всей сессии Websocket, он проявляет себя как singleton, но ограниченный только сессией WebSocket.

Жизненный цикл Bean

С бинами происходит множество процессов под капотом. Во многие можно вмешаться, добавив собственную логику в разные этапы жизненного цикла. Через следующие этапы проходит каждый отдельно взятый бин:
Инстанцирование объекта - техническое начало жизни бина, работа конструктора его класса;
Внедрение зависимостей - установка свойств из конфигурации бина;
Нотификация aware-интерфейсов - BeanNameAware, BeanFactoryAware и другие. Технически, выполняется системными подтипами BeanPostProcessor, и совпадает с шагом 4;
Пре-инициализация - метод postProcessBeforeInitialization() interface BeanPostProcessor;
Инициализация - разные способы применяются в таком порядке:
Метод бина с аннотацией @PostConstruct - из стандарта JSR-250 (рекомендуемый способ);
Метод - afterPropertiesSet() interface InitializingBean;
Init-метод - для отдельного бина его имя устанавливается в параметре определения initMethod. В xml-конфигурации можно установить для всех бинов сразу, с помощью default-init-method;
Пост-инициализация - метод postProcessAfterInitialization() interface BeanPostProcessor.
Уничтожение бина - Когда IoC-контейнер завершает свою работу, мы можем кастомизировать этот этап. Как со всеми способами финализации в Java, при жестком выключении (kill -9) гарантии вызова этого этапа нет. Три альтернативных способа «деинициализации» вызываются в том же порядке, что симметричные им методы инициализации:
Метод с аннотацией @PreDestroy;
Метод с именем, которое указано в свойстве destroyMethod определения бина (или в глобальном default-destroy-method);
Метод destroy() interface DisposableBean.
image.png
Жизненный цикл компонента состоит из семи этапов:
1. Создать экземпляр: Компонент создается контейнером Spring с использованием определения компонента, найденного в файле конфигурации XML.
2. Заполнение свойств: Spring заполняет все определенные свойства из XML-файла с помощью внедрения зависимостей.
3. Установить имя компонента: Spring передает идентификатор компонента методу setBeanName (), если компонент использует интерфейс BeanNameAware.
4. Установить baen factory: Spring передает beanfactory методу setBeanFactory (), если компонент настроен на использование интерфейса BeanFactoryAware.
5. Предварительная инициализация: Spring вызывает любые BeanPostProcessors, связанные с компонентом, с помощью метода postProcessorBeforeInitialization ().
6. Инициализация: Затем инициализируется компонент. Выполняется любой специальный процесс инициализации, указанный в методе инициализации.
7. Постинициализация: Вызываются все определенные методы postProcessAfterInitialization (). Теперь bean завершен. Компоненты, реализующие DisposableBean, будут удалены с помощью функции destroy() после завершения их работы.
image.png
Не путать жизненный цикл отдельного бина с жизненным циклом контекста и этапами подготовки фабрик бинов.

Типы Bean and Annotation

image.png

Основные аннотации

@SpringBootApplication - определяет автоматическое сканирование пакета, где находится главный класс. Если ваш код целиком находится в указанном пакете или его подпакетах - ОК, но если бин вне этого пакета, вы должны использовать аннотацию - ComponentScan, где перечислите дополнительные пакеты для сканирования. Эта аннотация включает другие:
@Configuration
@EnableAutoConfiguration
@ComponentScan - Показывает в каких пакетах и их под пакетах искать где искать бины.
@Bean - Ставится над методом в классе с аннотацией @Configuration. Он отделяет объявление компонента от определения класса и позволяет создавать и настраивать компоненты на ваше усмотрение.По умолчанию имя компонента совпадает с именем метода.
@Component / @Service / @Repository - Используется для автоматического обнаружения бинов, настраивает их спринг, между анноируемым классом и компонентом однозначное сопоставление.
@Service - Тоже самое что и Component но смысл что ставятся над классами с бизнес логику.
@Repository - Тоже самое что и Component но смысл что ставятся над классами с подключением к бд, также имеют обработку JDBC Exception.
@Autowired - Подставляет(Binding / Связывание) бин из контекста в нужное место: В сеттер, конструктор (если он один можно просто создать приватное поле без @Autowired, все равно будет инжект). Параметр required = false, если бин не найден не падает с NoSuchBeanDefinitionException. Best practice - не использовать @Autowired над полями:
Повышается coupling (сцепление = плохо) - внедрении прямо в поля вы не предоставляете прямого способа создания экземпляра класса со всеми необходимыми зависимостями.
Скрытие зависимостей - Когда класс более не отвечает за получение зависимостей, он должен явно взаимодействовать с ними, используя публичные интерфейсы — методы или конструкторы. Таким образом становится четко понятно, что требует класс, а также опциональные ли это зависомости (через сеттеры) или обязательные (конструктор).
Зависимость от DI-контейнера - класс не должен зависеть от конкретного используемого контейнера. Другими словами, это должен быть простой POJO-класс, экземпляр которого может быть создан самостоятельно, если вы передадите ему все необходимые зависимости. Таким образом, вы можете создать его в юнит-тесте без запуска контейнера и протестировать его отдельно.
@Qualifier / @Primary - Если бинов одного типа несколько (name1 и name2), способы:
inject @Qualifier(name1) - выбирает этот бин по имени.
над бином name1 @Primary - выбирает этот бин по умолчанию.
@Lazy - Если у нас цикличная зависимость бинов или Refactoring т.к плохая архитектура.

Web аннотации (используют Servlet)

@Controller - служит для авто обнаружения бина этого класса. Может вернуть – mvc view.
@RequestMapping(value = "/simple1") сообщаем, что данный метод контроллера или весь класс будет обрабатывать запрос, URI которого "/simple1". Если хотим вернуть данные @ResponseBody.
@ResponseBody - возаращает body значение в ответ на запрос, имеет статусы SUCCESS(200) и SERVER ERROR(500)
@ResponseEntity - если мы хотим кастомизировать ответ, добавив к нему статус. Во всех остальных случаях будем использовать @ResponseBody.
@RestController = @Controller + @ResponseBody - превращает помеченный класс в бин. Этот бин для конвертации входящих/исходящих данных использует Jackson. Как правило данные представлены в json или xml. Не возвращает view.

Другие аннотации

@Scheduled - запускает метод(задачу) по расписанию используя эту аннотацию. ​cron = "0 15 10 15 * ?", zone = "Europe/Paris" - запускать в 10:15 каждый 15-й день месяца по Парижу.
@ConditionalOnProperty(value="project.mq.enabled", matchIfMissing = false) - Самым распространенным способом управления контекстом спринга являются профили (@Profile). Они позволяют быстро и просто регулировать создание бинов. Но иногда может потребоваться более тонкая настройка.
Аннотация
Описание
1
ConditionalOnBean
в случае если присутствует нужный бин в BeanFactory.
2
ConditionalOnClass
если нужный класс есть в classpath.
3
ConditionalOnCloudPlatform
когда активна определенная платформа.
4
ConditionalOnExpression
когда SpEL выражение вернуло положительное значение.
5
ConditionalOnJava
когда приложение запущено с определенной версией JVM.
6
ConditionalOnJndi
только если через JNDI доступен определенный ресурс.
7
ConditionalOnMissingBean
в случае если нужный бин отсутствует в BeanFactory.
8
ConditionalOnMissingClass
если нужный класс отсутствует в classpath.
9
ConditionalOnNotWebApplication
если контекст приложения не является веб контекстом.
10
ConditionalOnProperty
если в файле настроек заданы нужные параметры.
11
ConditionalOnResource
если присутствует нужный ресурс в classpath.
12
ConditionalOnSingleCandidate
бин уже содержится в BeanFactory и он единственный.
13
ConditionalOnWebApplication
если контекст приложения является веб контекстом.
There are no rows in this table

Filters, Listeners, Interceptors

Filters - ИНТЕРФЕЙС из пакета javax.servlet, его имплементации выполняют фильтрацию. В веб-приложении мы можем написать несколько фильтров, которые вместе называются цепочкой фильтров. Выполняется, в соответствии с порядком регистрации фильтров.
Фильтры - это часть стандартного веб-контейнера (например, Apache Tomcat) и применяются до и после обработки запроса и ответа. Они могут обрабатывать HTTP-запросы и ответы, а также выполнять некоторые операции, такие как логирование, аутентификация, авторизация, фильтрация запросов и другие общие операции.
Фильтры находятся ниже уровня Spring и обрабатывают запросы и ответы независимо от контекста Spring.
В Spring вы также можете определить собственные фильтры, реализовав интерфейс javax.servlet.Filter.
Listeners - это класс, который реализует интерфейс javax.servlet.ServletContextListener. Он инициализируется только ОДИН раз при запуске веб-приложения. Слушатель ждет, когда произойдет указанное событие, затем «перехватывает» событие и запускает собственное событие.
Слушатели - это компоненты, которые позволяют приложению реагировать на различные события жизненного цикла веб-приложения, такие как запуск и остановка приложения, создание и уничтожение сессии, атрибуты контекста и другие события.
Слушатели также являются частью стандартного веб-контейнера и не специфичны для Spring.
В Spring вы можете определить свои собственные слушатели, реализовав интерфейсы javax.servlet.ServletContextListener или javax.servlet.http.HttpSessionListener.
Interceptors - Это ИНТЕРФЕЙС из пакета org.aopalliance.intercept, предназначенный для AOP аспектно-ориентированного программирования. Предположим, у нас есть простое веб-приложение Spring MVC, которое содержит один контроллер для обработки запроса на показ приветственного сообщения. Мы можем создать перехватчик, который будет записывать время обработки каждого запроса и выводить его в лог.
Перехватчики - это механизмы Spring MVC, которые позволяют вам встраиваться в процесс обработки запросов и ответов перед и после выполнения контроллеров.
Они работают на уровне Spring MVC и позволяют выполнять общие задачи, такие как аутентификация, логирование, изменение модели, контроль доступа и другие.
Перехватчики специфичны для Spring MVC и являются частью контекста Spring.
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.