前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >发现了Spring的bug,领导带我出去一起爬山玩水了

发现了Spring的bug,领导带我出去一起爬山玩水了

作者头像
JavaEdge
发布2021-02-22 16:12:49
3900
发布2021-02-22 16:12:49
举报
文章被收录于专栏:JavaEdge
  • 完全同步的AbstractRefreshableApplicationContext.getBeanFactory,可能导致大量线程阻塞:

在运行具有大量CPU 核的Tomcat的大型服务器上,由于同步块,在getBeanFactory()中看到大量线程阻塞。这是因为我们使用XmlWebApplicationContext,并且在Web请求期间每次查找bean时都需要bean工厂。

在Web应用程序之外,我们还使用GenericXmlApplicationContext拥有另一个上下文,而这个上下文没有此问题。

哪个代码路径通常会碰到那里的障碍? WebApplicationContext引用上某种形式的getBean查找,每次都在内部委派给BeanFactory吗?我们的内部查找通常会保留内部BeanFactory并直接对其进行操作,这也可能是定制检索代码的一种出路。

就是说,可以使用一些更细粒度的锁定来对这个(相当古老的,2008 年spring编写的锁)beanFactoryMonitor锁进行重做,以进行读取访问,甚至有可能用作访问的volatile字段以及(重新)初始化和关闭的专用锁。

案例

这是第一个有趣的纯Spring版本(TenantIgnoreXmlWebApplicationContext是我们的类,但没重写containsBean()或任何方式)。似乎每个通过org.springframework.web.multipart.support.MultipartFilter的请求始终在进行bean查找,并且总是在访问getBeanFactory()。

代码语言:javascript
复制
...
TenantIgnoreXmlWebApplicationContext(AbstractRefreshableApplicationContext).getBeanFactory() line: 175	
	TenantIgnoreXmlWebApplicationContext(AbstractApplicationContext).containsBean(String) line: 1146	
	MultipartFilter.lookupMultipartResolver() line: 157	
	MultipartFilter.lookupMultipartResolver(HttpServletRequest) line: 143	
	MultipartFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 108	
	MultipartFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 119	
	ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 193	
	ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 166	
	FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 320	
	FilterSecurityInterceptor.invoke(FilterInvocation) line: 127	
	FilterSecurityInterceptor.doFilter(ServletRequest, ServletResponse, FilterChain) line: 91	

确实,spring的某些过滤器实现以及某些Web集成的委托(比如JSF)在WebApplicationContext级别调用getBean方法,因此需要加锁。

尽管我们可以修改这些位置以保留嵌套的BeanFactory,但将AbstractRefreshableApplicationContext切换到volatile beanFactory字段似乎更具吸引力。由于AbstractApplicationContext已经应用了startupShutdownMonitor,因此我们应该能够完全摆脱beanFactoryMonitor,而始终访问volatile字段。

我不确定在哪里有嵌套的BeanFactory,因为在我们的堆栈,总是只有这两个方法位于我们自己对getBean(String)的调用之上:

  • org.springframework.context.support.AbstractApplicationContext.getBean(String,Class)调用
  • org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory()

当我们以下面的方式查找当前的Web应用程序上下文时,可能是在调用之前缺少了某些东西。 这是我们遗留代码库所需要的一种静态实用程序方法,以防万一。

代码语言:javascript
复制
	private static ApplicationContext getWebApplicationContextIfExists()
	{
		ServletContext servletContext = null;

		final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if (requestAttributes instanceof ServletRequestAttributes)
		{
			servletContext = ((ServletRequestAttributes) requestAttributes).getRequest().getServletContext();
		}

...
		if (servletContext != null)
		{
			final ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
			if (context == null)
			{
				if (log.isDebugEnabled())
				{
					log.debug("No web spring configuration for webapp " + servletContext.getServletContextName()
							+ " found, using only core configuration.");
				}
			}
			else
			{
…
				return context;

			}
		}
		return null;
	}

最终修改代码的提交

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/08/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 案例
  • 最终修改代码的提交
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档