Spring请求范围vs java thread-local

for*_*has 18 java spring thread-local

在大量(每秒约50,000个请求)java web-app我正在使用ThreadLocal来执行应该按请求范围执行的任务.

我可以使用Spring请求范围实现相同的效果,我想知道哪个性能更好?

在代码中,使用ThreadLocal:

private static final ThreadLocal<SomeClass> myThreadLocal = new ThreadLocal<SomeClass>();
Run Code Online (Sandbox Code Playgroud)

并为每个http请求设置:

myThreadLocal.set(new SomeClass());
Run Code Online (Sandbox Code Playgroud)

使用Spring请求范围:

@Component
@Scope("request")
public class SomeClass{
...
}
Run Code Online (Sandbox Code Playgroud)

现在,会花多少钱:

myThreadLocal.get();
Run Code Online (Sandbox Code Playgroud)

要么

SpringContext.getBean(SomeClass.class);
Run Code Online (Sandbox Code Playgroud)

我想知道是否有人已经尝试过这样的基准测试?

Bog*_*san 11

如果我们考虑传统的Java方法,答案可以从下面的引用中减去,因为它要慢得多:

由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化.因此,反射操作的性能低于非反射操作,并且应避免在性能敏感应用程序中频繁调用的代码段中.

引自JavaDoc的反思 - http://java.sun.com/docs/books/tutorial/reflect/index.html

如此以来,春季使用的反思getBean()方法的SpringContext.getBean(SomeClass.class);做法应该是比较慢.

编辑:

另请注意,嵌入式缓存ThreadLocal也是如此,只要您在这些线程中重复使用信息肯定会更快.


Art*_*kov 7

关于ThreadLocal解决方案,我想补充一点,您的Web服务器中可能存在一个线程池(例如:Tomcat),并且在完成每个请求后,您的线程局部变量实际上不会被清除,因为处理线程不会死于线程池已启用.

您需要threadLocal.remove()在收集每个请求时手动清除线程局部变量().为此,您可以使用afterCompletion()某些Spring请求/响应拦截器.


Sot*_*lis 6

Spring解决方案的成本会更高,但会使IMO更清晰.获取,创建,初始化和存储bean涉及许多步骤.但是,您不必考虑清除请求范围的bean ThreadLocal.在ServletRequest清理相应的内容时将收集它.