提交 92ff07de 编写于 作者: M Micha Kiener

SPR-6420, refactoring conversation scope for more simplicity

上级 5bfb99a7
...@@ -20,11 +20,10 @@ import java.util.List; ...@@ -20,11 +20,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.springframework.conversation.manager.ConversationManager; import org.springframework.conversation.manager.ConversationManager;
import org.springframework.conversation.scope.ConversationScope;
/** /**
* The interface for a conversation, the instance behind the * The interface for a conversation, the instance behind the
* {@link ConversationScope}.<br/> * {@link org.springframework.conversation.scope.ConversationScope}.<br/>
* Conversations are created through the {@link ConversationManager} which is * Conversations are created through the {@link ConversationManager} which is
* the main API for conversation management unless the annotations are used. See * the main API for conversation management unless the annotations are used. See
* {@link ConversationManager} for a more detailed description on how the * {@link ConversationManager} for a more detailed description on how the
......
...@@ -26,105 +26,68 @@ import org.springframework.conversation.JoinMode; ...@@ -26,105 +26,68 @@ import org.springframework.conversation.JoinMode;
import org.springframework.conversation.annotation.BeginConversation; import org.springframework.conversation.annotation.BeginConversation;
import org.springframework.conversation.annotation.Conversational; import org.springframework.conversation.annotation.Conversational;
import org.springframework.conversation.annotation.EndConversation; import org.springframework.conversation.annotation.EndConversation;
import org.springframework.conversation.scope.ConversationScope;
/** /**
* <p> * <p> The interface to be implemented by any conversation manager. It is used by the advice behind the conversational
* The interface to be implemented by any conversation manager. It is used by * annotations like {@link BeginConversation}, {@link EndConversation} and {@link Conversational} but might be used for
* the advice behind the conversational annotations like * even fine grained access to the underlying conversation management, if a initializer callback is needed for instance
* {@link BeginConversation}, {@link EndConversation} and {@link Conversational} * or if conversation switching should be used. If used directly, the conversation manager can be injected into any bean
* but might be used for even fine grained access to the underlying conversation * to be used as it is a singleton and thread safe.<br/>
* management, if a initializer callback is needed for instance or if *
* conversation switching should be used. If used directly, the conversation * Conversations are a good way to scope beans and attributes depending on business logic boundary rather than a
* manager can be injected into any bean to be used as it is a singleton and * technical boundary of a scope like session, request etc. Usually a conversation boundary is defined by the starting
* thread safe.<br/> * point of a use case and ended accordingly or in other words a conversation defines the boundary for a unit of
* * work.<br/> <br/>
* Conversations are a good way to scope beans and attributes depending on *
* business logic boundary rather than a technical boundary of a scope like * Here is a short description on how to use the conversation management:<br/> <br/> <b>Starting a conversation</b><br/>
* session, request etc. Usually a conversation boundary is defined by the * A conversation can be started in two different ways, either by placing the {@link BeginConversation} annotation on a
* starting point of a use case and ended accordingly or in other words a * method defining the starting point of the conversation (use case) or by invoking {@link
* conversation defines the boundary for a unit of work.<br/> * ConversationManager#beginConversation(boolean, JoinMode)} manually through the conversation manager. The {@link
* <br/> * JoinMode} declares on how a new conversation is created (see its javadoc for more details on the different join
* * modes).<br/> <br/>
* Here is a short description on how to use the conversation management:<br/> *
* <br/> * <b>Ending a conversation</b><br/> A current conversation is ended by either placing the {@link EndConversation}
* <b>Starting a conversation</b><br/> * annotation on the ending method or by manually invoke the {@link ConversationManager#endCurrentConversation(ConversationEndingType)}
* A conversation can be started in two different ways, either by placing the * method. A current conversation might also be ended, if a new conversation is started having {@link JoinMode#NEW}
* {@link BeginConversation} annotation on a method defining the starting point * being declared where the current conversation is ended silently and a new one is created. This might be the obvious
* of the conversation (use case) or by invoking * way to end a conversation, if the end of a use case is not always forced to be invoked by a user.<br/> <br/>
* {@link ConversationManager#beginConversation(boolean, JoinMode)} manually *
* through the conversation manager. The {@link JoinMode} declares on how a new * <b>Temporary conversations</b><br/> A temporary conversation is automatically created, if the container is about to
* conversation is created (see its javadoc for more details on the different * create a bean having conversation scope but there is no current conversation in progress, hence a new, temporary
* join modes).<br/> * conversation is created. A temporary conversation might be turned into a long running one by joining it or manually
* <br/> * invoke {@link Conversation#begin()}.<br/> <br/>
* *
* <b>Ending a conversation</b><br/> * <b>Initializing the conversation</b><br/> If there is any need to initialize beans or entities while starting a new
* A current conversation is ended by either placing the {@link EndConversation} * conversation, the {@link ConversationInitializationCallback} might be used to be invoked if the new conversation was
* annotation on the ending method or by manually invoke the * started in order to initialize it. This is done by providing such a callback to the {@link
* {@link ConversationManager#endCurrentConversation(ConversationEndingType)} * ConversationManager#beginConversation(JoinMode, ConversationType, ConversationInitializationCallback...)} method. The
* method. A current conversation might also be ended, if a new conversation is * callback feature is not available through the annotation support and hence is only available through the conversation
* started having {@link JoinMode#NEW} being declared where the current * manager API. Here is an example on such an initializing feature; if a conversation is used in conjunction of a JPA
* conversation is ended silently and a new one is created. This might be the * entity manager or Hibernate session, there might be entity beans already loaded, cached or referenced within backing
* obvious way to end a conversation, if the end of a use case is not always * beans which have to be merged into the entity manager or session in order to be used within the conversation's work.
* forced to be invoked by a user.<br/> * So it would be possible to implement the callback, merging the necessary entities used within the conversation into
* <br/> * the entity manager.<br/> <br/>
* *
* <b>Temporary conversations</b><br/> * <b>Listening to conversation events</b><br/> If there is a need to listening to events of a conversation, add
* A temporary conversation is automatically created, if the container is about * yourself as a {@link ConversationListener} to a new {@link Conversation} as being returned by this {@link
* to create a bean having conversation scope but there is no current * ConversationManager}. The same goal can be achieved by implementing the {@link ConversationListener} interface on a
* conversation in progress, hence a new, temporary conversation is created. A * conversation scoped bean which will be registered automatically to receive events.<br/> <br/>
* temporary conversation might be turned into a long running one by joining it *
* or manually invoke {@link Conversation#begin()}.<br/> * <b>Nesting conversations</b><br/> Conversations might be nested either by inheriting the state of the parent ( {@link
* <br/> * JoinMode#NESTED}) or by isolating its state from the parent ( {@link JoinMode#ISOLATED}). Ending a nested
* * conversation automatically switches back to its parent making it the current conversation.<br/> <br/>
* <b>Initializing the conversation</b><br/> *
* If there is any need to initialize beans or entities while starting a new * <b>Where are conversations stored?</b><br/> Conversations are created by the {@link ConversationManager} and
* conversation, the {@link ConversationInitializationCallback} might be used to * registered within the {@link org.springframework.conversation.scope.ConversationScope}. The scope handler is
* be invoked if the new conversation was started in order to initialize it. * injected into the manager by Spring (statically as both beans are singletons) and registered as a custom scope. As
* This is done by providing such a callback to the * the scope handler is a singleton, it needs a store where conversations are stored within which is usually bound to
* {@link ConversationManager#beginConversation(JoinMode, ConversationType, ConversationInitializationCallback...)} * the current session or window of a user and represented by the {@link ConversationStore} interface. The store is
* method. The callback feature is not available through the annotation support * usually being injected into the scope handler using method injection as the store has a narrower scope than the scope
* and hence is only available through the conversation manager API. Here is an * handler. In a web environment, the store would typically live in session scope to separate the conversations from
* example on such an initializing feature; if a conversation is used in * each of the sessions. There is always one current conversation either stored within the session or as a request
* conjunction of a JPA entity manager or Hibernate session, there might be * parameter passed along every request to set the current conversation and is accessed by the manager using a {@link
* entity beans already loaded, cached or referenced within backing beans which * ConversationResolver}. </p>
* have to be merged into the entity manager or session in order to be used *
* within the conversation's work. So it would be possible to implement the
* callback, merging the necessary entities used within the conversation into
* the entity manager.<br/>
* <br/>
*
* <b>Listening to conversation events</b><br/>
* If there is a need to listening to events of a conversation, add yourself as
* a {@link ConversationListener} to a new {@link Conversation} as being
* returned by this {@link ConversationManager}. The same goal can be achieved
* by implementing the {@link ConversationListener} interface on a conversation
* scoped bean which will be registered automatically to receive events.<br/>
* <br/>
*
* <b>Nesting conversations</b><br/>
* Conversations might be nested either by inheriting the state of the parent (
* {@link JoinMode#NESTED}) or by isolating its state from the parent (
* {@link JoinMode#ISOLATED}). Ending a nested conversation automatically
* switches back to its parent making it the current conversation.<br/>
* <br/>
*
* <b>Where are conversations stored?</b><br/>
* Conversations are created by the {@link ConversationManager} and registered
* within the {@link ConversationScope}. The scope handler is injected into the
* manager by Spring (statically as both beans are singletons) and registered as
* a custom scope. As the scope handler is a singleton, it needs a store where
* conversations are stored within which is usually bound to the current session
* or window of a user and represented by the {@link ConversationStore}
* interface. The store is usually being injected into the scope handler using
* method injection as the store has a narrower scope than the scope handler. In
* a web environment, the store would typically live in session scope to
* separate the conversations from each of the sessions. There is always one
* current conversation either stored within the session or as a request
* parameter passed along every request to set the current conversation and is
* accessed by the manager using a {@link ConversationResolver}.
* </p>
*
* @author Micha Kiener * @author Micha Kiener
* @since 3.1 * @since 3.1
*/ */
...@@ -132,7 +95,7 @@ public interface ConversationManager { ...@@ -132,7 +95,7 @@ public interface ConversationManager {
/** /**
* This method starts a new {@link Conversation} and registers it within the * This method starts a new {@link Conversation} and registers it within the
* {@link ConversationScope} to be exposed as the current conversation. * {@link org.springframework.conversation.scope.ConversationScope} to be exposed as the current conversation.
* *
* @param temporary flag indicating whether this new conversation is * @param temporary flag indicating whether this new conversation is
* temporary (if invoked from elsewhere as the scope, it should always be * temporary (if invoked from elsewhere as the scope, it should always be
......
...@@ -15,35 +15,213 @@ ...@@ -15,35 +15,213 @@
*/ */
package org.springframework.conversation.scope; package org.springframework.conversation.scope;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope; import org.springframework.beans.factory.config.Scope;
import org.springframework.conversation.Conversation;
import org.springframework.conversation.JoinMode;
import org.springframework.conversation.manager.ConversationManager;
import org.springframework.conversation.manager.ConversationResolver;
import org.springframework.conversation.manager.ConversationStore;
import org.springframework.util.Assert;
/** /**
* This interface is implemented by the conversation scope used to hold and * The default implementation of the {@link ConversationScope} exposed as
* expose conversation scoped beans. It will be registered as a custom scope * <code>"conversation"</code> scope. It needs the {@link ConversationStore} and
* within the application context. * the {@link ConversationResolver} to resolve and request the current
* conversation where attributes are resolved with and registered in.
* *
* @author Micha Kiener * @author Micha Kiener
* @since 3.1 * @since 3.1
*/ */
public interface ConversationScope extends Scope { public class ConversationScope implements Scope {
/** The name of the scope being exposed within the application context. */ /** The name of the scope being exposed within the application context. */
public static final String CONVERSATION_SCOPE_NAME = "conversation"; public static final String CONVERSATION_SCOPE_NAME = "conversation";
/** /**
* The name of the contextual object for the conversation manager (see * The name of the contextual object for the conversation manager (see
* {@link Scope#resolveContextualObject(String)}). * {@link org.springframework.beans.factory.config.Scope#resolveContextualObject(String)}).
*/ */
public static final String REFERENCE_CONVERSATION_MANAGER = "conversationManager"; public static final String REFERENCE_CONVERSATION_MANAGER = "conversationManager";
/** /**
* The name of the contextual object for the conversation store (see * The name of the contextual object for the conversation store (see
* {@link Scope#resolveContextualObject(String)}). * {@link org.springframework.beans.factory.config.Scope#resolveContextualObject(String)}).
*/ */
public static final String REFERENCE_CONVERSATION_STORE = "conversationStore"; public static final String REFERENCE_CONVERSATION_STORE = "conversationStore";
/** /**
* The name of the contextual object for the conversation resolver (see * The name of the contextual object for the conversation resolver (see
* {@link Scope#resolveContextualObject(String)}). * {@link org.springframework.beans.factory.config.Scope#resolveContextualObject(String)}).
*/ */
public static final String REFERENCE_CONVERSATION_RESOLVER = "conversationResolver"; public static final String REFERENCE_CONVERSATION_RESOLVER = "conversationResolver";
}
/** Holds the conversation manager reference, if statically injected. */
private ConversationManager conversationManager;
/** Holds the conversation store reference, if statically injected. */
private ConversationStore conversationStore;
/** Holds the conversation resolver reference, if statically injected. */
private ConversationResolver conversationResolver;
/**
* This method is invoked to resolve the current conversation used where
* attributes having conversation scope are being resolved with or stored
* in.
*
* @return the currently used conversation, or <code>null</code>, if no one
* currently available and <code>createIfNotExisting</code> is
* <code>false</code>
*/
protected Conversation getCurrentConversation(boolean createNewIfNotExisting) {
ConversationResolver resolver = getConversationResolver();
Assert.notNull(resolver, "No conversation resolver available within the conversation scope");
String conversationId = resolver.getCurrentConversationId();
Conversation conversation;
if (conversationId == null) {
if (createNewIfNotExisting) {
// start a new, temporary conversation using the default join
// mode
ConversationManager manager = getConversationManager();
conversation = manager.beginConversation(true, JoinMode.getDefaultJoinMode());
} else {
return null;
}
} else {
ConversationStore store = getConversationStore();
Assert.notNull(store, "No conversation store available within the conversation scope");
conversation = store.getConversation(conversationId);
Assert.notNull(conversation, "The conversation with id <" + conversationId
+ "> is not available within the store");
}
return conversation;
}
/**
* @see org.springframework.beans.factory.config.Scope#get(java.lang.String,
* org.springframework.beans.factory.ObjectFactory)
*/
public Object get(String name, ObjectFactory<?> objectFactory) {
Conversation conversation = getCurrentConversation(true);
Object attribute = conversation.getAttribute(name);
if (attribute == null) {
attribute = objectFactory.getObject();
conversation.setAttribute(name, attribute);
}
return attribute;
}
/**
* @see org.springframework.beans.factory.config.Scope#getConversationId()
*/
public String getConversationId() {
Conversation conversation = getCurrentConversation(false);
if (conversation != null) {
return conversation.getId();
}
return null;
}
/**
* @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String,
* java.lang.Runnable)
*/
public void registerDestructionCallback(String name, Runnable callback) {
Conversation conversation = getCurrentConversation(false);
if (conversation != null) {
conversation.registerDestructionCallback(name, callback);
}
}
/**
* @see org.springframework.beans.factory.config.Scope#remove(java.lang.String)
*/
public Object remove(String name) {
Conversation conversation = getCurrentConversation(false);
if (conversation != null) {
return conversation.removeAttribute(name);
}
return null;
}
/**
* Supports the following objects:
* <ul>
* <li><code>"conversationManager"</code>, returns the {@link ConversationManager}</li>
* <li><code>"conversationStore"</code>, returns the {@link ConversationStore}</li>
* <li><code>"conversationResolver"</code>, returns the {@link ConversationResolver}</li>
* </ul>
*
* @see org.springframework.beans.factory.config.Scope#resolveContextualObject(java.lang.String)
*/
public Object resolveContextualObject(String key) {
if (REFERENCE_CONVERSATION_MANAGER.equals(key)) {
return getConversationManager();
} else if (REFERENCE_CONVERSATION_STORE.equals(key)) {
return getConversationStore();
} else if (REFERENCE_CONVERSATION_RESOLVER.equals(key)) {
return getConversationResolver();
}
return null;
}
/**
* @param conversationManager the conversation manager reference to be used
* by this scope
*/
public void setConversationManager(ConversationManager conversationManager) {
this.conversationManager = conversationManager;
}
/**
* @return the conversation manager reference
*/
public ConversationManager getConversationManager() {
return conversationManager;
}
/**
* @param conversationStore the reference of the conversation store to be
* injected and internally used to request registered conversation objects
*/
public void setConversationStore(ConversationStore conversationStore) {
this.conversationStore = conversationStore;
}
/**
* Returns the reference of the conversation store to be used. If the store
* is not within the same scope as the conversation scope, this method has
* to be injected.
*
* @return the reference of the conversation store
*/
public ConversationStore getConversationStore() {
return conversationStore;
}
/**
* @param conversationResolver the reference of the conversation resolver
* used to determine the currently used conversation id
*/
public void setConversationResolver(ConversationResolver conversationResolver) {
this.conversationResolver = conversationResolver;
}
/**
* Returns the reference of the conversation resolver to be used. If the
* resolver is not within the same scope as the conversation scope, this
* method has to be injected.
*
* @return the reference of the conversation resolver
*/
public ConversationResolver getConversationResolver() {
return conversationResolver;
}
}
\ No newline at end of file
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.conversation.scope;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.conversation.Conversation;
import org.springframework.conversation.JoinMode;
import org.springframework.conversation.manager.ConversationManager;
import org.springframework.conversation.manager.ConversationResolver;
import org.springframework.conversation.manager.ConversationStore;
import org.springframework.util.Assert;
/**
* The default implementation of the {@link ConversationScope} exposed as
* <code>"conversation"</code> scope. It needs the {@link ConversationStore} and
* the {@link ConversationResolver} to resolve and request the current
* conversation where attributes are resolved with and registered in.
*
* @author Micha Kiener
* @since 3.1
*/
public class DefaultConversationScope implements ConversationScope{
/** Holds the conversation manager reference, if statically injected. */
private ConversationManager conversationManager;
/** Holds the conversation store reference, if statically injected. */
private ConversationStore conversationStore;
/** Holds the conversation resolver reference, if statically injected. */
private ConversationResolver conversationResolver;
/**
* This method is invoked to resolve the current conversation used where
* attributes having conversation scope are being resolved with or stored
* in.
*
* @return the currently used conversation, or <code>null</code>, if no one
* currently available and <code>createIfNotExisting</code> is
* <code>false</code>
*/
protected Conversation getCurrentConversation(boolean createNewIfNotExisting) {
ConversationResolver resolver = getConversationResolver();
Assert.notNull(resolver, "No conversation resolver available within the conversation scope");
String conversationId = resolver.getCurrentConversationId();
Conversation conversation;
if (conversationId == null) {
if (createNewIfNotExisting) {
// start a new, temporary conversation using the default join
// mode
ConversationManager manager = getConversationManager();
conversation = manager.beginConversation(true, JoinMode.getDefaultJoinMode());
} else {
return null;
}
} else {
ConversationStore store = getConversationStore();
Assert.notNull(store, "No conversation store available within the conversation scope");
conversation = store.getConversation(conversationId);
Assert.notNull(conversation, "The conversation with id <" + conversationId
+ "> is not available within the store");
}
return conversation;
}
/**
* @see org.springframework.beans.factory.config.Scope#get(java.lang.String,
* org.springframework.beans.factory.ObjectFactory)
*/
public Object get(String name, ObjectFactory<?> objectFactory) {
Conversation conversation = getCurrentConversation(true);
Object attribute = conversation.getAttribute(name);
if (attribute == null) {
attribute = objectFactory.getObject();
conversation.setAttribute(name, attribute);
}
return attribute;
}
/**
* @see org.springframework.beans.factory.config.Scope#getConversationId()
*/
public String getConversationId() {
Conversation conversation = getCurrentConversation(false);
if (conversation != null) {
return conversation.getId();
}
return null;
}
/**
* @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String,
* java.lang.Runnable)
*/
public void registerDestructionCallback(String name, Runnable callback) {
Conversation conversation = getCurrentConversation(false);
if (conversation != null) {
conversation.registerDestructionCallback(name, callback);
}
}
/**
* @see org.springframework.beans.factory.config.Scope#remove(java.lang.String)
*/
public Object remove(String name) {
Conversation conversation = getCurrentConversation(false);
if (conversation != null) {
return conversation.removeAttribute(name);
}
return null;
}
/**
* Supports the following objects:
* <ul>
* <li><code>"conversationManager"</code>, returns the
* {@link ConversationManager}</li>
* <li><code>"conversationStore"</code>, returns the
* {@link ConversationStore}</li>
* <li><code>"conversationResolver"</code>, returns the
* {@link ConversationResolver}</li>
* </ul>
*
* @see org.springframework.beans.factory.config.Scope#resolveContextualObject(java.lang.String)
*/
public Object resolveContextualObject(String key) {
if (ConversationScope.REFERENCE_CONVERSATION_MANAGER.equals(key)) {
return getConversationManager();
} else if (ConversationScope.REFERENCE_CONVERSATION_STORE.equals(key)) {
return getConversationStore();
} else if (ConversationScope.REFERENCE_CONVERSATION_RESOLVER.equals(key)) {
return getConversationResolver();
}
return null;
}
/**
* @param conversationManager the conversation manager reference to be used
* by this scope
*/
public void setConversationManager(ConversationManager conversationManager) {
this.conversationManager = conversationManager;
}
/**
* @return the conversation manager reference
*/
public ConversationManager getConversationManager() {
return conversationManager;
}
/**
* @param conversationStore the reference of the conversation store to be
* injected and internally used to request registered conversation objects
*/
public void setConversationStore(ConversationStore conversationStore) {
this.conversationStore = conversationStore;
}
/**
* Returns the reference of the conversation store to be used. If the store
* is not within the same scope as the conversation scope, this method has
* to be injected.
*
* @return the reference of the conversation store
*/
public ConversationStore getConversationStore() {
return conversationStore;
}
/**
* @param conversationResolver the reference of the conversation resolver
* used to determine the currently used conversation id
*/
public void setConversationResolver(ConversationResolver conversationResolver) {
this.conversationResolver = conversationResolver;
}
/**
* Returns the reference of the conversation resolver to be used. If the
* resolver is not within the same scope as the conversation scope, this
* method has to be injected.
*
* @return the reference of the conversation resolver
*/
public ConversationResolver getConversationResolver() {
return conversationResolver;
}
}
\ No newline at end of file
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
<bean id="conversationResolver" class="org.springframework.conversation.manager.ThreadAttachedConversationResolver" /> <bean id="conversationResolver" class="org.springframework.conversation.manager.ThreadAttachedConversationResolver" />
<bean id="conversationScope" class="org.springframework.conversation.scope.DefaultConversationScope" lazy-init="false"> <bean id="conversationScope" class="org.springframework.conversation.scope.ConversationScope" lazy-init="false">
<property name="conversationManager" ref="conversationManager"/> <property name="conversationManager" ref="conversationManager"/>
<property name="conversationStore" ref="conversationStore"/> <property name="conversationStore" ref="conversationStore"/>
<property name="conversationResolver" ref="conversationResolver"/> <property name="conversationResolver" ref="conversationResolver"/>
......
...@@ -15,22 +15,22 @@ ...@@ -15,22 +15,22 @@
*/ */
package org.springframework.web.conversation; package org.springframework.web.conversation;
import org.springframework.conversation.scope.DefaultConversationScope; import org.springframework.conversation.scope.ConversationScope;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
/** /**
* The extension of the default conversation scope ( * The extension of the default conversation scope (
* {@link DefaultConversationScope}) by supporting contextual web objects * {@link org.springframework.conversation.scope.ConversationScope}) by supporting contextual web objects
* returned by overwriting {@link #resolveContextualObject(String)}. * returned by overwriting {@link #resolveContextualObject(String)}.
* *
* @author Micha Kiener * @author Micha Kiener
* @since 3.1 * @since 3.1
*/ */
public class WebAwareConversationScope extends DefaultConversationScope { public class WebAwareConversationScope extends ConversationScope {
/** /**
* @see org.springframework.conversation.scope.DefaultConversationScope#resolveContextualObject(java.lang.String) * @see org.springframework.conversation.scope.ConversationScope#resolveContextualObject(java.lang.String)
*/ */
@Override @Override
public Object resolveContextualObject(String key) { public Object resolveContextualObject(String key) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册