简体   繁体   中英

Spring Boot autowire field in singleton service/controller by request scoped bean

I have a singleton service class with an autowired field like:

@Service
public class MyService{

     @Autowired
     private List<POJO> listWithObjectsForRequest;

}

the listWithObjectsForRequest is used im multiple services and components of my Spring Boot Application and a lot of calculations are required to create this list. It also depends on the current request that is running. So I thought I could write a request scoped bean, that will be injected by Spring every time a request enters my application:

@Configuration
public class MyServiceConfiguration{

    @Bean
    @RequestScope
    public List<POJO> listWithObjectsForRequest(){
        return heavyCalculations() // signature: public List<POJO> heavyCalculations()...
    }

}

But I get the following error on application startup:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myService': Unsatisfied dependency expressed through field 'listWithObjectsForRequest'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.listWithObjectsForRequest': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:596)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:374)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1247)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
    ... 31 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.listWithObjectsForRequest': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:365)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:193)
    at com.sun.proxy.$Proxy84.equals(Unknown Source)
    at java.util.concurrent.ConcurrentHashMap.containsValue(ConcurrentHashMap.java:985)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.determineAutowireCandidate(DefaultListableBeanFactory.java:1501)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1222)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1167)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
    ... 44 common frames omitted
Caused by: java.lang.IllegalStateException: 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: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
    at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:42)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:353)
    ... 53 common frames omitted

I thought I found the answer here: Inject request scoped bean into another bean but my application still fails with this error message.

I know that the listWithObjectsForRequest can only be calculated in request scope, but how to tell spring that the field of MyService should only be initialized (once) in request?

You will get this exception because you are trying to inject request scope into singleton. Singleton will be created once and dependency will be injected once. You might be using some functionality which is depended on request, and during bean initialization of singleton, spring is unable to find it.

If you want to inject request scope bean into singleton you can do this by either

Inject ApplicationContext into MyService like -

        @Autowired
        private ApplicationContext context;

Then instead of autowiring listWithObjectsForRequest, get bean reference from the application context every time. Though this approach will solve the issue, but will bound your code with the Spring. If you are OK with it you can use it.

Or

You can use method injection as mentioned here - https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-method-injection

As already mentioned in other answers, you are getting this error because of injecting request scoped bean into a singleton scoped bean aka narrower bean DI problem

You just need to use

@Autowired // provider from javax.inject.Provider; private Provider<List<POJO>> listWithObjectsForRequest;

References When to use javax.inject.Provider in Spring?

在类POJO中,在类声明之前尝试@Scope(“ prototype”)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM