Accessing a request scoped bean in a different thread (that handles websocket traffic)

血红的双手。 提交于 2020-01-06 05:51:06

问题


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:

  1. 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.

  2. 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!).

  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!