Вопрос : Как я могу сказать Spring, что набор bean-компонентов с настраиваемой областью действия должен рассматриваться как мусор, чтобы следующий запрос в том же потоке не использовал их состояние?
Что я сделал : я реализовал пользовательскую область в Spring, чтобы имитировать жизненный цикл области запроса (HttpRequest), но для TcpRequests.Это очень похоже на то, что найдено здесь .
Множество примеров пользовательских областей видимости, которые я нахожу, представляют собой варианты прототипа или синглтона без явного завершения бинов или, в качестве альтернативы, они основаны навокруг локального потока или ThreadScope, но они не описывают сообщение Spring о том, что жизненный цикл закончился и все компоненты должны быть уничтожены.
То, что я пробовал (возможно, неправильно):
Событие + Прослушиватель для указания начала и конца области (это происходит при получении сообщения и непосредственно перед отправкой ответа);в слушателе область явно очищается, что очищает всю карту, используемую локальной реализацией потока (scope.clear ()).Очистка области действия приводит к следующему вызову context.getBean (), возвращающему новый экземпляр при обработке вручную в тестах, но мой bean-компонент, который автоматически подключается в одноэлементном классе, не получает новый bean-компонент - он использует один и тот же bean-компонент снова и снова.
Слушатель, который реализует: BeanFactoryPostProcessor, BeanPostProcessor, BeanFactoryAware, DisposableBean и пытается вызвать destroy () для всех экземпляров одноразового компонента;что-то вроде это , но только для моей пользовательской области.Похоже, что это не помогает, поскольку ничто явно не завершает жизненный цикл bean-компонентов, несмотря на то, что я вызываю customScope.clear (), когда получаю событие окончания области;завершение области, по-видимому, не переводится как «конец всех bean-компонентов, связанных с этой областью».
Я много читал документацию Spring и, похоже, ясно, что Spring неуправлять жизненным циклом этих пользовательских bean-компонентов, так как он не знает, когда и как они должны быть уничтожены, а это означает, что необходимо указать, когда и как их уничтожить;Я попытался прочитать и понять области Session и Request, предоставленные Spring, чтобы я мог имитировать это, но что-то упустил (опять же, они недоступны для меня, поскольку это не веб-приложение, и я неиспользуя HttpRequests, и это нетривиальное изменение в структуре нашего приложения)
Кто-нибудь может указать мне правильное направление?
У меня есть следующеепримеры кода:
Конфигурация Xml-контекста :
<int-ip:tcp-connection-factory id="serverConnectionFactory" type="server" port="19000"
serializer="javaSerializer" deserializer="javaDeserializer"/>
<int-ip:tcp-inbound-gateway id="inGateway" connection-factory="serverConnectionFactory"
request-channel="incomingServerChannel" error-channel="errorChannel"/>
<int:channel id="incomingServerChannel" />
<int:chain input-channel="incomingServerChannel">
<int:service-activator ref="transactionController"/>
</int:chain>
TransactionController (обрабатывает запрос) :
@Component("transactionController")
public class TransactionController {
@Autowired
private RequestWrapper requestWrapper;
@ServiceActivator
public String handle(final Message<?> requestMessage) {
// object is passed around through various phases of application
// object is changed, things are added, and finally, a response is generated based upon this data
tcpRequestCompletePublisher.publishEvent(requestWrapper, "Request lifecycle complete.");
return response;
}
}
TcpRequestScope (определение области действия) :
@Component
public class TcpRequestScope implements Scope {
private final ThreadLocal<ConcurrentHashMap<String, Object>> scopedObjects =
new InheritableThreadLocal<ConcurrentHashMap<String, Object>>({
@Override
protected ConcurrentHashMap<String, Object> initialValue(){
return new ConcurrentHashMap<>();
}
};
private final Map<String, Runnable> destructionCallbacks =
Collections.synchronizedMap(new HashMap<String, Runnable>());
@Override
public Object get(final String name, final ObjectFactory<?> objectFactory) {
final Map<String, Object> scope = this.scopedObjects.get();
Object object = scope.get(name);
if (object == null) {
object = objectFactory.getObject();
scope.put(name, object);
}
return object;
}
@Override
public Object remove(final String name) {
final Map<String, Object> scope = this.scopedObjects.get();
return scope.remove(name);
}
@Override
public void registerDestructionCallback(final String name, final Runnable callback) {
destructionCallbacks.put(name, callback);
}
@Override
public Object resolveContextualObject(final String key) {
return null;
}
@Override
public String getConversationId() {
return String.valueOf(Thread.currentThread().getId());
}
public void clear() {
final Map<String, Object> scope = this.scopedObjects.get();
scope.clear();
}
}
TcpRequestCompleteListener :
@Component
public class TcpRequestCompleteListener implements ApplicationListener<TcpRequestCompleteEvent> {
@Autowired
private TcpRequestScope tcpRequestScope;
@Override
public void onApplicationEvent(final TcpRequestCompleteEvent event) {
// do some processing
// clear all scope related data (so next thread gets clean slate)
tcpRequestScope.clear();
}
}
RequestWrapper (объект, который мы используем на протяжении жизненного цикла запроса) :
@Component
@Scope(scopeName = "tcpRequestScope", proxyMode =
ScopedProxyMode.TARGET_CLASS)
public class RequestWrapper implements Serializable, DisposableBean {
// we have many fields here which we add to and build up during processing of request
// actual request message contents will be placed into this class and used throughout processing
@Override
public void destroy() throws Exception {
System.out.print("Destroying RequestWrapper bean");
}
}