Какой области видимости нет в spring
Перейти к содержимому

Какой области видимости нет в spring

  • автор:

Бины и область видимости — Java: Корпоративные приложения на Spring Boot

В Spring бином называется объект, который управляется, создается и настраивается Spring-контейнером. Эти объекты создаются на базе конфигурации, которая задается с помощью аннотаций. Только эти объекты участвуют в инъекции зависимостей при сборке Spring-приложения.

Конфигурация

Далее мы рассмотрим два способа создания бинов.

Создание бинов на основе классов

Если мы просто создадим класс и попытаемся внедрить его объект с помощью аннотации @Autowired , то ничего не получится. Spring никак не реагирует на обычные классы. Чтобы превратить этот класс в бин, нужно пометить его аннотацией, например:

  • @Component — любой класс общего назначения, объект которого мы хотим получить в приложении
  • @Repository — репозитории
  • @RestController — контроллеры

Изучим пример с репозиторием:

package io.hexlet.spring.repository; import hexlet.code.model.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository // Во время компиляции этот интерфейс превращается в конкретный класс public interface UserRepository extends JpaRepositoryUser, Long>  > 

Внедрение происходит так:

@RestController @RequestMapping("/users") public class UserController  @Autowired private UserRepository userRepository; > 

Создание бинов на основе методов

В реальных проектах внедряться могут не только объекты классов, реализованные программистом. Еще можно внедрять объекты классов, которые находятся в библиотеках. Например, есть известная библиотека datafaker , которая используется в тестах для генерации данных. Работает она так:

import net.datafaker.Faker; var faker = new Faker(); var name = faker.name().fullName(); // Miss Samanta Schmidt var firstName = faker.name().firstName(); // Emory var lastName = faker.name().lastName(); // Barton var streetAddress = faker.address().streetAddress(); // 60018 Sawayn Brooks Suite 449 

Существует два основных способа использования этой библиотеки внутри Spring Boot. Первый – это создание объекта напрямую в том месте, где мы хотим его использовать. В примере с Faker мы будем создавать и использовать объект внутри теста:

@SpringBootTest @AutoConfigureMockMvc public class UsersControllerTest  @BeforeEach public void setUp()  var faker = new Faker(); // Тут создаем нужные данные > 

Второй – это создание бина с помощью метода. Для этого нам нужно создать метод внутри любого класса, помеченного аннотацией @Configuration . Проще всего это сделать в классе с методом main , потому что аннотация @SpringBootApplication автоматически добавляет аннотацию @Configuration :

@SpringBootApplication public class Application  public static void main(String[] args)  SpringApplication.run(Application.class, args); > @Bean public Faker getFaker()  // Имя метода не важно return new Faker(); > > 

Теперь Faker можно внедрять как обычную зависимость:

@SpringBootTest @AutoConfigureMockMvc public class UsersControllerTest  @Autowired private Faker faker; @BeforeEach public void setUp()  // Тут создаем нужные данные > 

Жизненный цикл бинов

У бинов есть понятие жизненного цикла, что позволяет встраиваться в процесс их создания и уничтожения. Делается это с помощью аннотаций методов @PostConstruct и @PreDestroy внутри класса нужного бина:

import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Component; @Component public class MyBean  private String message; @PostConstruct public void init()  this.message = "Bean is initialized!"; System.out.println(message); > @PreDestroy public void cleanup()  System.out.println("Cleaning up resources or performing final actions!"); > // . other methods . > 

Типичные ситуации, когда это бывает нужно:

  • Чтение конфигурации и инициализация некоторых свойств
  • Установка ресурсов, таких как соединение с базой данных
  • Регистрация бинов во внешних системах

Область видимости бинов

Область видимости бинов определяет жизненный цикл и саму видимость бинов внутри контекста приложения. Другими словами, она определяет, сколько объектов создается и как они переиспользуются разными частями приложения. Всего существует шесть областей видимости.

По умолчанию используется область Singleton. Бины с такой областью создаются ровно один раз за все время существования приложения. Каждая инъекция такого бина использует один и тот же объект.

Область Prototype означает, что новый бин будет создан на каждый запрос (инъекцию):

import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.stereotype.Component; @Scope("prototype") @Component public class PrototypeBean <> 

Область Request означает, что новый бин создается на каждый HTTP-запрос. Актуально только для веб-приложений:

import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.RequestScope; @RequestScope @Component public class RequestScopedBean <> 

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов

Наши выпускники работают в компаниях:

Области видимости Singleton и Prototype в Spring

Управление осуществляется только одним общим экземпляром бина-одиночки, а все запросы к бинам с идентификатором или идентификаторами, соответствующими определению этого бина, приводят к тому, что контейнер Spring возвращает именно этот экземпляр бина.

Иными словами, когда вы назначаете определение бина и он входит в область видимости singleton, IoC-контейнер Spring создает ровно один экземпляр объекта, назначенного этим определением бина. Этот единственный экземпляр хранится в кэше таких бинов-одиночек, а все последующие запросы и ссылки на этот именованный бин возвращают кэшированный объект. На следующем изображении показано, как работает область видимости singleton:

Понятие бина-одиночки в Spring отличается от понятия шаблона-одиночки, определенного в книге о шаблонах «Банды четырёх» (Gang of Four/GoF). В случае объекта-одиночки GoF область видимости объекта жестко кодируется таким образом, что для каждого ClassLoader создается один и только один экземпляр конкретного класса. Область видимости одиночки в Spring лучше всего описать как per-container и per-bean. Это означает, что если вы определяете один бина для конкретного класса в одном контейнере Spring, контейнер Spring создает один и только один экземпляр класса, заданного этим определением бина. Область видимости singleton — это область видимости Spring по умолчанию. Чтобы определить бин как объект-одиночку в XML, вы можете определить бина способом, показанным в следующем примере:

Область видимости prototype

Не-singleton область видимости prototype для развертывания бина создает новый экземпляр бина каждый раз, когда выполняется запрос на этот конкретный бин. То есть бин внедряется в другой бин или запрашивается через вызов метода getBean() в контейнере. Как правило, следует использовать область видимости prototype для всех бинов, сохраняющих состояние, и область видимости singleton для бинов, не сохраняющих состояние.

Следующая схема иллюстрирует область видимости prototype в Spring:

(Объект доступа к данным (DAO) обычно не конфигурируется как прототип, потому что типичный DAO не сохраняет никакого диалогового состояния. Было проще повторно использовать ядро схемы для объекта-одиночки).

В следующем примере бин определяется как прототип в XML:

В отличие от других областей видимости, Spring не управляет полным жизненным циклом бина-прототипа. Контейнер создает экземпляр, конфигурирует и иным образом компонует объект-прототип и передает его клиенту, без дальнейших записей об этом экземпляре прототипа. Таким образом, хотя методы обратного вызова жизненного цикла инициализации вызываются для всех объектов независимо от области видимости, в случае прототипов, сконфигурированные обратные вызовы жизненного цикла разрушения не вызываются. Клиентский код должен подчищать объекты, входящие в область видимости prototype, и высвободить ценные ресурсы, которые потребляют бины-прототипы. Чтобы заставить контейнер Spring высвободить ресурсы, потребляемые бинами, входящими в область видимости prototype, попробуйте использовать специальный постпроцессор бинов, содержащий ссылку на бины, которые необходимо подчистить.

В некотором смысле роль контейнера Spring в отношении бинов, входящих в область видимости prototype, является заменой оператора Java new . Все управление жизненным циклом после данного момента должно осуществляться с клиентской стороны. (Подробнее о жизненном цикле бина в контейнере Spring см. в разделе Обратные вызовы жизненного цикла).

Бины-одиночки с зависимостями прототип-бин

Если вы используете бины, находящиеся в области видимости singleton, и с зависимостью от бинов-прототипов, помните, что зависимости разрешаются при создании экземпляра. Таким образом, если внедрять зависимость от бина-прототипа в бин, находящийся в области видимости singleton, создается экземпляр нового бина-прототипа, а затем внедряется в бин-одиночку. Экземпляр прототипа — это единственный экземпляр, который предоставляется бину, находящемуся в области видимости singleton.

Однако, предположим, вам нужно, чтобы бин, находящийся в области видимости singleton, неоднократно получал новый экземпляр бина, находящегося в области видимости prototype, во время выполнения. У вас не получится внедрить зависимость от бина, находяшегося в области видимости prototype, в ваш бин-одиночку, потому что внедрение происходит только один раз, когда контейнер Spring создает экземпляр бина-одиночки, разрешает и внедряет его зависимости.

Области видимости Request, Session, Application, и WebSocket в Spring

Области видимости request , session , application и websocket доступны, только если вы используете реализацию ApplicationContext в фреймворке Spring с поддержкой веб (например, XmlWebApplicationContext ). Если вы используете эти области видимости с обычными IoC-контейнерами Spring, такими как ClassPathXmlApplicationContext , будет сгенерирован IllegalStateException c сообщением о неизвестной области видимости бина.

Начальная веб-конфигурация

Для поддержки создания области видимости бинов на уровне request , session , application и websocket (web-scoped бины) перед определением бина требуется провести небольшую начальную настройку. (Данная начальная настройка не требуется для стандартных областей видимости: singleton и prototype ).

То, каким образом вы выполните эту начальную настройку, зависит от вашей конкретной среды сервлетов.

Если вы обращаетесь к бинам, находящимся в области видимости, в Spring Web MVC, то есть в рамках запроса, который обрабатывается Spring DispatcherServlet , никакой специальной настройки не требуется. DispatcherServlet уже раскрывает все соответствующие состояния.

Если вы используете веб-контейнер Servlet 2.5, в котором запросы обрабатываются вне Spring DispatcherServlet (например, при использовании JSF или Struts), вам необходимо зарегистрировать org.springframework.web.context.request.RequestContextListener ServletRequestListener . Для Servlet 3.0+ это можно сделать программно, используя интерфейс WebApplicationInitializer . В качестве альтернативы или для более старых версий контейнеров добавьте следующее объявление в файл web web.xml вашего веб-приложения:

 .  org.springframework.web.context.request.RequestContextListener  . 

В качестве альтернативы, если есть проблемы с настройкой слушателя, рассмотрите возможность использования RequestContextFilter в Spring. Отображение фильтров зависит от окружающей конфигурации веб-приложения, поэтому вы должны изменить его соответствующим образом. В следующем листинге показана часть фильтра веб-приложения:

 . requestContextFilter org.springframework.web.filter.RequestContextFilter  requestContextFilter /*  . 

DispatcherServlet , RequestContextListener и RequestContextFilter делают одно и то же, а именно связывают объект HTTP-запроса с Thread , который обслуживает этот запрос. Это позволяет получить доступ к бинам, входящим в область видимости request или session, далее по цепочке вызовов.

Область видимости request

Рассмотрим следующую XML-конфигурацию для определения бина:

Контейнер Spring создает новый экземпляр бина LoginAction с помощью определения бина loginAction для каждого HTTP-запроса. То есть бин loginAction находится в области видимости на уровне HTTP-запроса. Можно сколько угодно изменять внутреннее состояние создаваемого экземпляра, поскольку другие экземпляры, созданные на основе того же определения бина loginAction , не видят этих изменений состояния. Они зависят от конкретного запроса. Если запрос завершает обработку, бин, находящийся в области видимости запроса, исключается.

При использовании компонентов, управляемых аннотациями, или конфигурации Java, аннотацию @RequestScope можно использовать для назначения компонента области видимости request . В следующем примере показано, как это сделать:

@RequestScope @Component public class LoginAction < // . >
@RequestScope @Component class LoginAction < // . >

Область видимости в пределах сеанса

Рассмотрим следующую XML-конфигурацию для определения бина:

Контейнер Spring создает новый экземпляр бина UserPreferences с помощью определения бина userPreferences на время жизни одной HTTP Session . Иными словами, бин userPreferences эффективно располагается в области видимости на уровне HTTP Session . Как и в случае с бинами, находящимися в области видимости request, вы можете изменять внутреннее состояние созданного экземпляра сколько угодно, зная, что другие экземпляры HTTP Session , которые также используют экземпляры, созданные на основе того же определения бина userPreferences , не заметят этих изменений состояния, поскольку они относятся к отдельной HTTP Session . Если HTTP Session в конечном итоге исключается, бин, который привязан к этой конкретной HTTP Session , также исключается.

При использовании компонентов, управляемых аннотациями, или конфигурации Java можно использовать аннотацию @SessionScope , чтобы назначить компонент области видимости session .

@SessionScope @Component public class UserPreferences < // . >
@SessionScope @Component class UserPreferences < // . >

Область видимости в пределах приложения

Рассмотрим следующую XML-конфигурацию для определения бина:

Контейнер Spring создает новый экземпляр бина AppPreferences , используя определение бина appPreferences единожды для всего веб-приложения. То есть бин appPreferences находится в области видимости на уровне ServletContext и хранится как обычный атрибут ServletContext . Он в некоторой степени похож на бин-одиночку Spring, но отличается от него двумя важными особенностями: Он является объектом-одиночкой для каждого ServletContext , а не для Spring ApplicationContext (которых может быть несколько в любом конкретном веб-приложении), и он фактически открывается, поэтому и виден как атрибут ServletContext .

При использовании компонентов, управляемых аннотациями, или конфигурации Java можно использовать аннотацию @ApplicationScope для назначения компонента области видимости application . В следующем примере показано, как это сделать:

@ApplicationScope @Component public class AppPreferences < // . >
@ApplicationScope @Component class AppPreferences < // . >

Область видимости в пределах WebSocket

Область видимости WebSocket связана с жизненным циклом сессии WebSocket и применяется к приложениям STOMP over WebSocket.

Руководство по Spring. Конфигурирование с помощью Java.

В предыдущих постах мы уже рассмотрели конфигурацию в Spring с помощью XML-файлов.

Но стоит упомянуть, что в Spring Framework поддерживается конфигурация с помощью Java, что временами бывает удобно. Это позволяет нам настроить большую часть Spring-приложения без использования конфигурационного файла XML, используя специальные аннотации.

В конфигурации с помощью аннотаций Java, ключевыми являются @Configuration и @Bean

@Configuration

Эта аннотация, прописанная перед классом, означает, что класс может быть использован контейнером Spring IoC как конфигурационный класс для бинов.

@Bean

Аннотация @Bean, прописанная перед методом, информирует Spring о том, что возвращаемый данным методом объект должен быть зарегистрирован, как бин.

В простейшем случае, это может выглядеть так, как показано в простом приложении, приведённом ниже.

Исходный код проекта можно скачать по ЭТОЙ ССЫЛКЕ.

javaConfigStructure

javaConfigMessage

javaConfigMessageConfig

javaConfigMessageRunner

Результат работы программы

javaConfigResult

Но это всего лишь простейший случай. Если же нам необходимо внедрить какую-либо зависимость, то это будет выглядеть так, как показано в приложении, приведённом ниже.

Исходный код проекта можно скачать по ЭТОЙ ССЫЛКЕ.

javaConfigExamStructure

javaConfigExam

javaConfigAnswerChecker

javaConfigExamConfig

javaConfigExamRunner

Результат работы программы

javaConfigExamResult

И в заключение приведём простые пример того, как должны выглядеть классы, если мы хотим настроить область видимости (scope) класса с помощью Java-аннотаций.

Настройка области видимости (scope) бина:

javaConfigScope

В этой статье мы ознакомились с основами конфигурации Spring-приложения с помощью Java-аннотаций.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *