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

Создание специальной области видимости

Чтобы интегрировать специальные области видимости в контейнер Spring, необходимо реализовать интерфейс org.springframework.beans.factory.config.Scope, который описан в этом разделе. Чтобы получить представление о том, как реализовать специальные области видимости, ознакомьтесь с реализациями Scope, поставляемыми с самим Spring Framework, а также с javadoc Scope, в котором более подробно описаны методы, которые нужно реализовать.

Интерфейс Scope имеет четыре метода для получения объектов из области видимости, удаления их из области видимости и разрешения их уничтожения.

Например, реализация области видимости session возвращает скопированный бин, входящий в область видимости session (если такового не существует, метод возвращает новый экземпляр бина, привязав его к сессии для дальнейшего использования). Следующий метод возвращает объект из базовой области видимости:

Java
Object get(String name, ObjectFactory<?> objectFactory)
Kotlin
fun get(name: String, objectFactory: ObjectFactory<*>): Any

Например, реализация области видимости на уровне сессии удаляет бин, входящий в область видимости на уровне сессии, из базовой сессии. Объект должен быть возвращен, но может вернуться null, если объект с указанным именем не будет найден. Следующий метод удаляет объект из базовой области видимости:

Java
Object remove(String name)
Kotlin
fun remove(name: String): Any

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

Java
void registerDestructionCallback(String name, Runnable destructionCallback)
Kotlin
fun registerDestructionCallback(name: String, destructionCallback: Runnable)

Более подробную информацию об обратных вызовах уничтожения см. в javadoc или в реализации области видимости в Spring.

Следующий метод получает диалоговый идентификатор для базовой области видимости:

Java
String getConversationId()
Kotlin
fun getConversationId(): String

Этот идентификатор отличается для каждой области видимости. Для реализации на уровне области видимости session этот идентификатор может быть идентификатором сессии.

Использование специальной области видимости

После написания и тестирования одной или нескольких специальных реализаций Scope, нужно сделать так, чтобы контейнер Spring узнал о ваших новых областях видимости. Следующий метод является главным методом регистрации нового Scope в контейнере Spring:

Java
void registerScope(String scopeName, Scope scope);
Kotlin
fun registerScope(scopeName: String, scope: Scope)

Этот метод объявляется в интерфейсе ConfigurableBeanFactory, который доступен через свойство BeanFactory в большинстве конкретных реализаций ApplicationContext, поставляемых в составе Spring.

Первым аргументом метода registerScope(..) является уникальное имя, связанное с областью видимости. Примерами таких имен в самом контейнере Spring являются singleton и prototype. Вторым аргументом метода registerScope(..) является реальный экземпляр специальной реализации Scope, который вы хотите зарегистрировать и использовать.

Предположим, что вы написали свою собственную реализацию Scope, а затем зарегистрировали ее, как показано в следующем примере.

В следующем примере используется SimpleThreadScope, который входит в состав Spring, но не регистрируется по умолчанию. Инструкции будут такими же для ваших собственных специальных реализаций Scope.
Java
Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);
Kotlin
val threadScope = SimpleThreadScope()
beanFactory.registerScope("thread", threadScope)

Затем вы можете создать определения бинов, которые будут соответствовать правилам определения области видимости вашей пользовательской реализации Scope, как показано ниже:

<bean id="..." class="..." scope="thread">

При использовании пользовательской реализации Scope вы не ограничены программной регистрацией области видимости. Вы также можете произвести регистрацию Scope декларативно, используя класс CustomScopeConfigurer, как показано в следующем примере:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="thread">
                    <bean class="org.springframework.context.support.SimpleThreadScope"/>
                </entry>
            </map>
        </property>
    </bean>
    <bean id="thing2" class="x.y.Thing2" scope="thread">
        <property name="name" value="Rick"/>
        <aop:scoped-proxy/>
    </bean>
    <bean id="thing1" class="x.y.Thing1">
        <property name="thing2" ref="thing2"/>
    </bean>
</beans>
Когда вы помещаете <aop:scoped-proxy/> в объявление <bean> для реализации FactoryBean, в область видимости входит сам фабричный бин, а не объект, возвращаемый из getObject().