问题
I am having issues accessing a bean that is defined with a request centric scope in a thread that is not the request's thread.
My scenario is as follows:
Execution starts from a REST request coming from a client. In this request I define a bean that allows me to access data in a DB. The location of the DB depends on the user performing the request itself, hence why the bean with which the db is accessed is bound to the request itself. I get the user details from the request's auth and use them to init the bean.
During the HTTP request the code may call to an external service over a websocket connection. The ws traffic is handled by different
StompFrameHandler
classes. When these handle traffic they do so on a dedicated thread, which is not the same as the initial http request (and rightfully so!).- Some of these
StompFrameHandler
classes need to access the DB relevant to the user in context for the current (REST) request.
At 3 is where I encounter the issue:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I understand what the error is telling me and the fact that due to how I have defined my bean (request scope bound) spring does not allow me to access it in other threads. However I still need to use that db accessing bean from the ws traffic handling thread.
Here is a simplified version of my code:
The bean configuration:
@Configuration
public class DbClientRequestScopeConfiguration {
private DbClientFactoryI dbClientFactory;
private AuthenticationFacadeI authenticatedUserInfo;
@Autowired
public DbClientRequestScopeConfiguration(DbClientFactoryI dbClientFactory, AuthenticationFacadeI authenticatedUserInfo) {
this.dbClientFactory = dbClientFactory;
this.authenticatedUserInfo = authenticatedUserInfo;
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public DbClientI getDbClient() {
Authentication auth = authenticatedUserInfo.getAuthentication();
return dbClientFactory.getDbClient(auth.getDetails());
}
}
The DataService using the bean (this runs in the request's thread)
@Service
public class DataService {
private DbClientI dbClient;
@Autowired
public DataService(DbClientI dbClient) {
this.dbClient = dbClient;
}
...
}
The frame handler working with the WS traffic Note that this in not initialised by Spring's context, instead it is manually initialised by a class running in the request's thread, which gives it the instance of the @DataService coming from the Context.
public class SaveDataFrameHandler implements StompFrameHandler{
private DataService dataService;
public SaveDataFrameHandler(DataService dataService) {
this.dataService = dataService;
}
@Override
public Type getPayloadType(StompHeaders headers) {
return JsonNode.class;
}
@Override
public void handleFrame(StompHeaders headers, Object payload) {
// This method will be called on a separate thread
JsonNode jsonPayload = (JsonNode) payload;
dataService.saveRecord(jsonPayload);
}
}
I am looking for suggestions on how I could actually use that bean in my ws thread or how to rearchitect the solution so that I do not run into this problem.
Thanks in advance!
UPDATE:
I have managed to get around the problem for now even though I am not 100% happy with the solution. To avoid repetition, I posted my current solution in a new question, since I am facing a different issue now still related to this code: Proxied prototype bean is created every time a method is invoked from it
来源:https://stackoverflow.com/questions/53444273/accessing-a-request-scoped-bean-in-a-different-thread-that-handles-websocket-tr