Skip to content

ConcurrentModificationException in DispatcherServlet with asynchronous ApplicationEventMulticaster [SPR-17442] #21974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Oct 29, 2018 · 4 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Oct 29, 2018

Jared Wiltshire opened SPR-17442 and commented

We are occasionally seeing a ConcurrentModificationException thrown from DispatcherServlet.initHandlerMappings(ApplicationContext context) due to the sorting of the handler mappings from two different threads (DispatcherServlet line 590 in 5.0.10).

I traced the cause of this back to our use of SimpleApplicationEventMulticaster with an asynchronous task executor.

What is happening is that FrameworkServlet.initWebApplicationContext() calls configureAndRefreshWebApplicationContext(cwac) which fires off a ContextRefreshedEvent. This results in onApplicationEvent(ContextRefreshedEvent event) being called from an executor thread which then calls onRefresh(event.getApplicationContext()). Further down in initWebApplicationContext() (FrameworkServlet line 557) it checks the boolean refreshEventReceived and calls onRefresh(wac) again from the main thread as there is no synchronization.

 


Affects: 5.0.10

Issue Links:

Backported to: 5.0.11

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

I've revised this towards an AtomicBoolean onRefreshTriggered which is being explicitly checked in both places now. Whoever gets there first takes the token and is responsible for the actual onRefresh call. In particular, if the ContextRefreshedEvent happens to come after the initWebApplicationContext() phase (as in your scenario), it will simply be ignored now.

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

Turns out it's not quite as straightforward since we support DispatcherServlet re-refreshs, as rarely as that may be used in practice...

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

On review, full synchronization of the onRefresh callback seems to be necessary for all scenarios to work correctly, in combination with the existing refreshEventReceived flag which skips an unnecessary re-refresh on initial setup in a regular single-threaded bootstrap scenario.

@spring-projects-issues
Copy link
Collaborator Author

Jared Wiltshire commented

Thanks Juergen Hoeller for looking at this. Fix looks good.

@spring-projects-issues spring-projects-issues added type: bug A general bug status: backported An issue that has been backported to maintenance branches in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.1.3 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants