Guice and RequestScoped behaviour in multiple threads

后端 未结 3 2024
情深已故
情深已故 2021-01-06 08:04

I am using Guice\'s RequestScoped and Provider in order to get instances of some classes during a user request. This works fine currently. Now I want to do some job in a bac

3条回答
  •  悲哀的现实
    2021-01-06 08:44

    I recently solved this exact problem. There are a few things you can do. First, read up on ServletScopes.continueRequest(), which wraps a callable so it will execute as if it is within the current request. However, that's not a complete solution because it won't forward @RequestScoped objects, only basic things like the HttpServletResponse. That's because @RequestScoped objects are not expected to be thread safe. You have some options:

    • If your entire @RequestScoped hierarchy is computable from just the HTTP response, you're done! You will get new instances of these objects in the other thread though.

    • You can use the code snippet below to explicitly forward all RequestScoped objects, with the caveat that they will all be eagerly instantiated.

    • Some of my @RequestScoped objects couldn't handle being eagerly instantiated because they only work for certain requests. I extended the below solution with my own scope, @ThreadSafeRequestScoped, and only forwarded those ones.

    Code sample:

    public class RequestScopePropagator {
        private final Map, Provider> requestScopedValues = new HashMap<>();
    
        @Inject
        RequestScopePropagator(Injector injector) {
            for (Map.Entry, Binding> entry : injector.getAllBindings().entrySet()) {
                Key key = entry.getKey();
                Binding binding = entry.getValue();
                // This is like Scopes.isSingleton() but we don't have to follow linked bindings
                if (binding.acceptScopingVisitor(IS_REQUEST_SCOPED)) {
                    requestScopedValues.put(key, binding.getProvider());
                }
            }
        }
    
        private final BindingScopingVisitor IS_REQUEST_SCOPED = new BindingScopingVisitor() {
            @Override
            public Boolean visitScopeAnnotation(Class scopeAnnotation) {
                return scopeAnnotation == RequestScoped.class;
            }
    
            @Override
            public Boolean visitScope(Scope scope) {
                return scope == ServletScopes.REQUEST;
            }
    
            @Override
            public Boolean visitNoScoping() {
                return false;
            }
    
            @Override
            public Boolean visitEagerSingleton() {
                return false;
            }
        };
    
        public  Callable continueRequest(Callable callable) {
            Map, Object> seedMap = new HashMap<>();
            for (Map.Entry, Provider> entry : requestScopedValues.entrySet()) {
                // This instantiates objects eagerly
                seedMap.put(entry.getKey(), entry.getValue().get());
            }
    
            return ServletScopes.continueRequest(callable, seedMap);
        }
    }
    

提交回复
热议问题