Java spring bean scope

Краткое руководство по Spring Bean Scopes

В этом кратком руководстве мы узнаем о различных типах областей действия компонентов в среде Spring.

Область действия bean-компонента определяет жизненный цикл и видимость этого bean-компонента в контекстах, в которых мы его используем.

Последняя версия фреймворка Spring определяет 6 типов областей видимости:

  • синглтон
  • прототип
  • запрос
  • сеанс
  • заявление
  • веб-сокет

Последние четыре упомянутые области, request, session, application и websocket , доступны только в веб-приложении.

2. Одноэлементный объем

Когда мы определяем bean-компонент с областью singleton , контейнер создает один экземпляр этого bean-компонента; все запросы для этого имени компонента будут возвращать один и тот же объект, который кэшируется. Любые изменения объекта будут отражены во всех ссылках на компонент. Эта область является значением по умолчанию, если не указана другая область.

Давайте создадим сущность Person , чтобы проиллюстрировать концепцию областей видимости:

 public class Person    private String name;    // standard constructor, getters and setters   > 

После этого мы определяем bean-компонент с областью singleton , используя аннотацию @Scope :

 @Bean   @Scope("singleton")   public Person personSingleton()    return new Person();   > 

Мы также можем использовать константу вместо значения String следующим образом:

 @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON) 

Теперь мы можем приступить к написанию теста, который показывает, что два объекта, ссылающиеся на один и тот же компонент, будут иметь одинаковые значения, даже если только один из них изменит свое состояние, так как они оба ссылаются на один и тот же экземпляр компонента:

 private static final String NAME = "John Smith";    @Test   public void givenSingletonScope_whenSetName_thenEqualNames()    ApplicationContext applicationContext =   new ClassPathXmlApplicationContext("scopes.xml");    Person personSingletonA = (Person) applicationContext.getBean("personSingleton");   Person personSingletonB = (Person) applicationContext.getBean("personSingleton");    personSingletonA.setName(NAME);   Assert.assertEquals(NAME, personSingletonB.getName());    ((AbstractApplicationContext) applicationContext).close();   > 

Файл scopes.xml в этом примере должен содержать XML-определения используемых bean-компонентов:

    beans xmlns="http://www.springframework.org/schema/beans"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">    bean id="personSingleton" class="org.foreach.scopes.Person" scope="singleton"/>   beans> 

3. Объем прототипа

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

 @Bean   @Scope("prototype")   public Person personPrototype()    return new Person();   > 

Мы также можем использовать константу, как мы делали для одноэлементной области видимости:

 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) 

Теперь мы напишем аналогичный тест, который показывает, как два объекта запрашивают одно и то же имя компонента с областью действия прототипа . У них будут разные состояния, поскольку они больше не относятся к одному и тому же экземпляру компонента:

 private static final String NAME = "John Smith";   private static final String NAME_OTHER = "Anna Jones";    @Test   public void givenPrototypeScope_whenSetNames_thenDifferentNames()    ApplicationContext applicationContext =   new ClassPathXmlApplicationContext("scopes.xml");    Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");   Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");    personPrototypeA.setName(NAME);   personPrototypeB.setName(NAME_OTHER);    Assert.assertEquals(NAME, personPrototypeA.getName());   Assert.assertEquals(NAME_OTHER, personPrototypeB.getName());    ((AbstractApplicationContext) applicationContext).close();   > 

Файл scopes.xml аналогичен файлу, представленному в предыдущем разделе, но добавляет определение xml для bean-компонента с областью действия прототипа :

 bean id="personPrototype" class="org.foreach.scopes.Person" scope="prototype"/> 

4. Веб-области действия

Как упоминалось ранее, есть четыре дополнительных области, которые доступны только в контексте веб-приложения. Мы используем их реже на практике.

Область запроса создает экземпляр компонента для одного HTTP-запроса, а область сеанса создает экземпляр компонента для сеанса HTTP.

Область приложения создает экземпляр компонента для жизненного цикла ServletContext , а область веб- сокета создает его для определенного сеанса веб-сокета .

Давайте создадим класс для создания экземпляров bean-компонентов:

 public class HelloMessageGenerator    private String message;    // standard getter and setter   > 

4.1. Объем запроса

Мы можем определить bean-компонент с областью запроса , используя аннотацию @Scope :

 @Bean   @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)   public HelloMessageGenerator requestScopedBean()    return new HelloMessageGenerator();   > 

Атрибут proxyMode необходим, поскольку в момент создания экземпляра контекста веб-приложения нет активного запроса. Spring создает прокси для внедрения в качестве зависимости и создает экземпляр целевого компонента, когда это необходимо в запросе.

Мы также можем использовать составную аннотацию @RequestScope , которая действует как ярлык для приведенного выше определения:

 @Bean   @RequestScope   public HelloMessageGenerator requestScopedBean()    return new HelloMessageGenerator();   > 

Далее мы можем определить контроллер, который имеет внедренную ссылку на requestScopedBean . Нам нужно дважды получить доступ к одному и тому же запросу, чтобы протестировать области, специфичные для Интернета.

Если мы будем отображать сообщение каждый раз, когда выполняется запрос, мы увидим, что значение сбрасывается на null , даже если позже оно было изменено в методе. Это связано с тем, что для каждого запроса возвращается другой экземпляр компонента.

 @Controller   public class ScopesController    @Resource(name = "requestScopedBean")   HelloMessageGenerator requestScopedBean;    @RequestMapping("/scopes/request")   public String getRequestScopeMessage(final Model model)    model.addAttribute("previousMessage", requestScopedBean.getMessage());   requestScopedBean.setMessage("Good morning!");   model.addAttribute("currentMessage", requestScopedBean.getMessage());   return "scopesExample";   >   > 

4.2. Область сеанса

Аналогичным образом мы можем определить bean-компонент с областью действия сеанса :

 @Bean   @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)   public HelloMessageGenerator sessionScopedBean()    return new HelloMessageGenerator();   > 

Также есть специальная составная аннотация, которую мы можем использовать для упрощения определения bean-компонента:

 @Bean   @SessionScope   public HelloMessageGenerator sessionScopedBean()    return new HelloMessageGenerator();   > 

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

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

 @Controller   public class ScopesController    @Resource(name = "sessionScopedBean")   HelloMessageGenerator sessionScopedBean;    @RequestMapping("/scopes/session")   public String getSessionScopeMessage(final Model model)    model.addAttribute("previousMessage", sessionScopedBean.getMessage());   sessionScopedBean.setMessage("Good afternoon!");   model.addAttribute("currentMessage", sessionScopedBean.getMessage());   return "scopesExample";   >   > 

4.3. Область применения

Область приложения создает экземпляр компонента для жизненного цикла ServletContext.

Это похоже на область действия singleton , но есть очень важное отличие в отношении области действия bean-компонента.

Когда bean -компоненты ограничены приложением , один и тот же экземпляр bean-компонента совместно используется несколькими приложениями на основе сервлетов, работающими в одном и том же ServletContext , в то время как bean -компоненты с областью действия singleton ограничены только одним контекстом приложения.

Давайте создадим bean-компонент с областью применения :

 @Bean   @Scope(   value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)   public HelloMessageGenerator applicationScopedBean()    return new HelloMessageGenerator();   > 

По аналогии с областями запроса и сеанса мы можем использовать более короткую версию:

 @Bean   @ApplicationScope   public HelloMessageGenerator applicationScopedBean()    return new HelloMessageGenerator();   > 

Теперь давайте создадим контроллер, который ссылается на этот компонент:

 @Controller   public class ScopesController    @Resource(name = "applicationScopedBean")   HelloMessageGenerator applicationScopedBean;    @RequestMapping("/scopes/application")   public String getApplicationScopeMessage(final Model model)    model.addAttribute("previousMessage", applicationScopedBean.getMessage());   applicationScopedBean.setMessage("Good afternoon!");   model.addAttribute("currentMessage", applicationScopedBean.getMessage());   return "scopesExample";   >   > 

В этом случае, однажды установленное в applicationScopedBean , сообщение со значением будет сохранено для всех последующих запросов, сеансов и даже для различных приложений сервлетов, которые будут обращаться к этому bean-компоненту, при условии, что он работает в том же ServletContext.

4.4. Область действия веб-сокета

Наконец, давайте создадим bean-компонент с областью действия websocket :

 @Bean   @Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)   public HelloMessageGenerator websocketScopedBean()    return new HelloMessageGenerator();   > 

При первом доступе bean-компоненты с областью действия WebSocket сохраняются в атрибутах сеанса WebSocket . Затем один и тот же экземпляр компонента возвращается при каждом доступе к этому компоненту в течение всего сеанса WebSocket .

Мы также можем сказать, что он демонстрирует одноэлементное поведение, но ограниченное только сеансом WebSocket .

5. Вывод

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

Реализацию этой статьи можно найти в проекте GitHub .

Источник

Читайте также:  And bit java indir
Оцените статью