0

I'm trying instantiate a component object for which I declared the <bean> entry in applicationContext.xml. The flow to instantiate my target component class is as follows

CalculateController -> CalculateService -> CalculateComponent

Where

CalculatorController - scope = request, annotated with @Controller and included in component scan in webapplicationContext.xml

CalculatorService - Scope = singleton, annotated with @service and included in component scan in applicationContext.xml

CalculateComponent - scope = request, no annotation, excluded from component scan in both webapplicationConext.xml and applicationContext.xml. Defined bean entry in webApplicationContext.xml with scope = request. Also include <aop:scoped-proxy/> in the <bean> definition.

I have included the following entry in web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
            classpath:spring/applicationContext.xml
            /WEB-INF/mvc-dispatcher-servlet.xml
            ....Other resource xmls
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- To retrieve session related information -->
<listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>

<listener>
    <listener-class>
            org.springframework.web.context.request.RequestContextListener 
    </listener-class>
</listener> 


<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

note that, the CalculateComponent has a 3 parameter ref object constructor and all three of them has <bean> entry in webApplicationContext.xml with singleton scope and they are not annotated.

When the request send to create the CalculateComponent object, spring container throwing the following error.

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

Please advise.

Update:

When I removed /WEB-INF/mvc-dispatcher-servlet.xml from contextConfigLocation and started the server, I got the Autowired failed error - "No qualifying bean of type CalculateComponent found for dependency:", even after I changed the scope from request to singleton.

Then I commented out the Autowiring of CalculateComponent in CalculateService and I can now see the CalculateComponent initiated twice (as mentioned my @Serge Ballesta). So I concluded that the CalculateService is initiated via ContextLoaderListener (bean entry in applicationContext.xml), before the DispatcherServlet is loaded(i.e no bean mentioned in mvc-dispatcher-servlet is loaded).

I added the /WEB-INF/mvc-dispatcher-servlet.xml back again in contextConfigLocation, but this time as the first entry (i.e on top of applicationContext.xml). Now the CalculateComponent loaded twice again and the Autowiring was done with singleton scope. With this setup I changed the CalculateComponent scope back to request, but again "I got the No thread-bound request found" error.

So the issue is,

ContextLoaderListener trying to initiaze the resources of DispatcherServlet(CalculateComponent) before its loaded / available.

gopal
  • 63
  • 1
  • 9

2 Answers2

0

It is weird to have a request scoped controller ... AFAIK, the framework expects it to be a singleton. Try to put it in a singleton scope.

And I think that you have all beans from /WEB-INF/mvc-dispatcher-servlet.xml instantiated twice :

  • first in root application context as is is declared in global contextConfigLocation
  • next in the servlet application context of the servlet named mvc-dispatcher

You should either rename the file, so it is not loader as a servlet application context, or remove it from root context

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • I removed the @scope value from all the controllers and removed the entry /WEB-INF/mvc-dispatcher-servlet.xml from context-param. Now when I start the server, I'm getting the error "No qualifying bean of type CalculateComponent found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value="BeanDefNameForCalcualteComponenet" – gopal May 28 '15 at 15:21
  • @Gopal : It is now a more *standard* error ... As you use a proxy to wire a request scoped bean in a singleton, the `CalculateComponent` must be wired as an interface , because by default Spring uses JDK proxies. You could force usage of javassist class proxies (`proxy_target_class = true`) but never mix both. – Serge Ballesta May 28 '15 at 15:35
  • Thanks for your replies. Adding to the request scoped bean isn't suffice for proxying the class. I also added cglib in my pom.xml. – gopal May 28 '15 at 15:40
  • @Gopal : yes it is effectively cglib you correctly fixed my comment :-) – Serge Ballesta May 28 '15 at 15:46
  • If you can see from my question, I'm using aop scoped proxy for the request scoped beans, but I'm still getting the error. Please advise. – gopal May 28 '15 at 15:49
0

Answering my own question. As I mentioned in my question this is my flow to get the request scoped component bean.

CalculateController -> CalculateService -> CalculateComponent.

But the CalculateController was invoked through an async request. We cannot access the web scoped beans from the async request thread.

Reference: How to enable request scope in async task executor

Community
  • 1
  • 1
gopal
  • 63
  • 1
  • 9