Механізм визначення області видимості бінів є розширюваним. Ти можеш визначити власні області видимості або навіть перевизначити існуючі, хоча останнє вважається порочною практикою, а також ти не можеш перевизначити вбудовані області видимості 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().