Skip to content

Synchronization issues occur on a form which heavily uses [SPR-9084] #13722

@spring-projects-issues

Description

@spring-projects-issues

Daniel Mikusa opened SPR-9084 and commented

Given a Spring MVC application which uses the Spring Forms JSP tags for data binding, a page that has a large number of field can cause blocking to occur.

Attached is a thread dump from an actual application which is experiencing this problem. Also attached is a sample application which can be used to demonstrate the problem.

To run the demo, use the command "mvn:tomcat". Once the application is deployed to Tomcat, run the included JMeter test to put load on the application. As the JMeter test runs, you should see the "max" time gradually increasing. I let it run for about 5 minutes and the max time crept up to around 10 seconds per response. Taking a thread dump at this time should show the issue.

In addition, I've ran the demo, replicating the problem, and have taken a snapshot with YourKit. The snapshot is attached.

From the snapshot, it appears that a significant portion of the contention appears to be around the following two items:

http-8080-8 [BLOCKED] CPU time: 0:03
java.util.Collections$SynchronizedMap.get(Object)
org.springframework.core.GenericTypeResolver.getTypeVariableMap(Class)
org.springframework.core.GenericTypeResolver.resolveParameterType(MethodParameter, Class)
org.springframework.core.convert.Property.resolveParameterType(MethodParameter)
org.springframework.core.convert.Property.resolveReadMethodParameter()
org.springframework.core.convert.Property.resolveMethodParameter()
org.springframework.core.convert.Property.<init>(Class, Method, Method)
org.springframework.beans.BeanWrapperImpl.property(PropertyDescriptor)
org.springframework.beans.BeanWrapperImpl.getPropertyTypeDescriptor(String)
org.springframework.validation.AbstractPropertyBindingResult.formatFieldValue(String, Object)
org.springframework.validation.AbstractBindingResult.getFieldValue(String)
org.springframework.web.servlet.support.BindStatus.<init>(RequestContext, String, boolean)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus()
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath()
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName()
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId()
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId()
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(TagWriter)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(TagWriter)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(TagWriter)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal()
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag()
org.apache.jsp.WEB_002dINF.views.home_jsp._jspx_meth_form_005finput_005f0(JspTag, PageContext, int[])
org.apache.jsp.WEB_002dINF.views.home_jsp._jspService(HttpServletRequest, HttpServletResponse)
org.apache.catalina.core.ApplicationDispatcher.forward(ServletRequest, ServletResponse)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(Map, HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.view.AbstractView.render(Map, HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.DispatcherServlet.render(ModelAndView, HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.DispatcherServlet.doService(HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.FrameworkServlet.processRequest(HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.FrameworkServlet.doPost(HttpServletRequest, HttpServletResponse)
java.lang.Thread.run()

and

http-8080-18 [BLOCKED] CPU time: 0:00
java.util.Arrays.equals(Object[], Object[])
org.springframework.util.ObjectUtils.nullSafeEquals(Object, Object)
org.springframework.core.convert.TypeDescriptor.equals(Object)
org.springframework.core.convert.support.GenericConversionService$ConverterCacheKey.equals(Object)
java.util.concurrent.ConcurrentHashMap.get(Object)
org.springframework.core.convert.support.GenericConversionService.getConverter(TypeDescriptor, TypeDescriptor)
org.springframework.core.convert.support.GenericConversionService.canConvert(TypeDescriptor, TypeDescriptor)
org.springframework.validation.AbstractPropertyBindingResult.formatFieldValue(String, Object)
org.springframework.validation.AbstractBindingResult.getFieldValue(String)
org.springframework.web.servlet.support.BindStatus.<init>(RequestContext, String, boolean)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus()
org.springframework.web.servlet.tags.form.ErrorsTag.shouldRender()
org.springframework.web.servlet.tags.form.AbstractHtmlElementBodyTag.writeTagContent(TagWriter)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal()
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag()
org.apache.jsp.WEB_002dINF.views.home_jsp._jspService(HttpServletRequest, HttpServletResponse)
org.apache.catalina.core.ApplicationDispatcher.forward(ServletRequest, ServletResponse)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(Map, HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.view.AbstractView.render(Map, HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.DispatcherServlet.render(ModelAndView, HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.DispatcherServlet.doService(HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.FrameworkServlet.processRequest(HttpServletRequest, HttpServletResponse)
org.springframework.web.servlet.FrameworkServlet.doPost(HttpServletRequest, HttpServletResponse)
java.lang.Thread.run()

The first item appears to be similar to what is mentioned here in #13343. The second item appears to be unique.


Affects: 3.0.6, 3.1 GA

Attachments:

Referenced from: commits 17bbc62, 9e21d2f

2 votes, 2 watchers

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions