Pet*_*der 11 java singleton spring session-scope
Singleton无法自动装配SessionBean,但ScopedProxy可以.
假设100个用户在同一个应用程序中同时拥有一个有效的Session,ScopedProxy如何决定会话的含义?
我不认为ScopedProxy正在选择任何随机会话,这在我看来是无稽之谈.
NullPointerException发生吗?Ren*_*nov 11
ThreadLocal几乎就是您正在寻找的答案.
该类提供线程局部变量.这些变量与它们的正常对应物的不同之处在于,访问一个变量的每个线程(通过其get或set方法)都有自己独立初始化的变量副本.
Spring有RequestContextHolder
Holder类以线程绑定的RequestAttributes对象的形式公开Web请求.如果可继承标志设置为true,则当前线程生成的任何子线程将继承该请求.
在课堂上你会看到以下内容:
private static final ThreadLocal<RequestAttributes> requestAttributesHolder =
new NamedThreadLocal<RequestAttributes>("Request attributes");
Run Code Online (Sandbox Code Playgroud)
这是实际的setter(注意它是静态的):
/**
* Bind the given RequestAttributes to the current thread.
* @param attributes the RequestAttributes to expose,
* or {@code null} to reset the thread-bound context
* @param inheritable whether to expose the RequestAttributes as inheritable
* for child threads (using an {@link InheritableThreadLocal})
*/
public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) {}
Run Code Online (Sandbox Code Playgroud)
所以,正如你所看到的那样,没有魔法,只有一个特定于线程的变量,由ThreadLocal.提供.
如果你是足够的好奇,这里是ThreadLocal.get实现(whic返回当前线程的这个线程局部变量的副本中的值):
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它只依赖于ThreadLocalMap:
/**
* ThreadLocalMap is a customized hash map suitable only for
* maintaining thread local values. No operations are exported
* outside of the ThreadLocal class. The class is package private to
* allow declaration of fields in class Thread. To help deal with
* very large and long-lived usages, the hash table entries use
* WeakReferences for keys. However, since reference queues are not
* used, stale entries are guaranteed to be removed only when
* the table starts running out of space.
*/
static class ThreadLocalMap {
Run Code Online (Sandbox Code Playgroud)
getEntry()在地图中执行查找.我希望你现在看到整个画面.
关于潜在的NullPointerException
基本上,只有在作用域处于活动状态时才能调用代理的方法,这意味着执行线程应该是一个servlet请求.因此,任何异步作业,命令等都将失败.
我想说,这背后是一个很大的问题ScopedProxy.它确实透明地解决了一些问题(简化了调用链,对于examaple),但是如果你不遵守规则,你可能会得到java.lang.IllegalStateException: No thread-bound request found
(Spring Framework Reference Documentation)说明如下:
DispatcherServlet,RequestContextListener和RequestContextFilter都完全相同,即将HTTP请求对象绑定到为该请求提供服务的Thread.这使得请求和会话范围的bean可以在调用链中进一步使用.
您还可以检查以下问题:在多线程Web应用程序中访问请求范围的bean
@Async和请求属性注入
一般来说,没有直接的方法来解决问题.如前所示,我们有线程绑定的RequestAttributes.
可能的解决方案是手动传递所需的对象,并确保后面的逻辑@Async考虑到这一点.
一个更聪明的解决方案(Eugene Kuleshov建议)是透明地做到这一点.我将复制代码以简化阅读并将链接放在代码块下.
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
/**
* @author Eugene Kuleshov
*/
public abstract class RequestAwareRunnable implements Runnable {
private final RequestAttributes requestAttributes;
private Thread thread;
public RequestAwareRunnable() {
this.requestAttributes = RequestContextHolder.getRequestAttributes();
this.thread = Thread.currentThread();
}
public void run() {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
onRun();
} finally {
if (Thread.currentThread() != thread) {
RequestContextHolder.resetRequestAttributes();
}
thread = null;
}
}
protected abstract void onRun();
}
Run Code Online (Sandbox Code Playgroud)
这是一个问题:在Threads中访问作用域代理bean
正如您所看到的,此解决方案依赖于事实构造函数将在适当的上下文中执行,因此可以缓存适当的上下文并在以后注入它.
这是另一个非常有趣的话题@Async注释方法,挂在会话范围的bean上
| 归档时间: |
|
| 查看次数: |
1553 次 |
| 最近记录: |