0

I have a method with @PostConstruct annotation which uses autowired service

@Service
public ServiceWithPostConstruct{

private AutowiredService autowiredService;

    @Autowired
    public ServiceWithPostConstruct(AutowiredService autowiredService) {
        this.autowiredService= autowiredService;
    }

    @PostConstruct
    public void doSomething() {
    autowiredService.doSomethingElse();
    }
}

AutowiredService declaration

@Component
public class AutowiredService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AutowiredService .class);

    private static final String SUCCESS_CODE = "0";

    private RestOperations restOperations;

    @Autowired
    public AutowiredService (RestOperations restOperations) {
        this.restOperations = restOperations;
    }
///
}

somewhere else in the code, I have a completely unrelated component, which has a scope = request

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ScopedService{
}

and listener in web.xml

org.springframework.web.context.request.RequestContextListener

this service works correctly, where it is used.

However while starting the application, I get the following error:

12-Dec-2017 13:24:15.221 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'controller' defined in file [controller.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serviceWithPostConstruct': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.scopedService': 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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

This error might have been understood if I would be autowiring the mentioned ScopedService. But clearly I am not. I don't understand, why this @PostConstruct method has anything to do with ScopedService. If I remove the @PostConstruct annotation problem disappears. And the ScopedService works everywhere as intended, in Singletons as well. However, only if I get rid of the @PostConstruct annotation. Unfortunately, I need to keep it.

I am certain that the use of autowired service in doSomething() method is the core of the problem, if I remove the autowired service, the application starts correctly. It seems, that because of this @PostConstruct method, Spring checks ALL services, and when it comes to the ScopedService (the only component with scope=request) it recognizes that in that moment there is no HttpRequest and throws an error. Why? It is not connected in any way with that ScopedService.

What can be done about that? I will appreciate any ideas.

majki
  • 33
  • 1
  • 8
  • AutowiredService doesn't have a dependency on ScopedService? – Uladzislau Kaminski Dec 13 '17 at 14:17
  • Well the `autowiredService` isn't really `autowired`, is it? Get rid of the constructor and declare the service member as `@Autowired private AutowiredService autowiredService;`. – daniu Dec 13 '17 at 14:17
  • @UladzislauKaminski no, it does not - completely unrelated – majki Dec 13 '17 at 14:19
  • @daniu Doesn't the "@Autowired" annotation at constructor do the same job as a separate "@Autowired" setter? – majki Dec 13 '17 at 14:21
  • hmmm going through the documentation it looks like you're right, I never used it that way... – daniu Dec 13 '17 at 14:23
  • 1
    @daniu i changed it anyway to your suggestion, unfortunately the same error – majki Dec 13 '17 at 14:31
  • Well in the Exception trace, there's also mention of a bean `scopedTarget`. Where does that come from? And maybe show the `AutowiredService` declaration. – daniu Dec 13 '17 at 14:35
  • Instead of using JSR-250's `@PostConstruct`, can you try using Spring's InitializingBean interface? It shouldn't do the trick but you have nothing to lose... – Nico Van Belle Dec 13 '17 at 14:37
  • the "scopedTarget" comes from the fact, that ScopedService has a declared scope - as explained here http://forum.spring.io/forum/spring-projects/web/45681-spring-session-scope-related-what-is-scopedtarget – majki Dec 13 '17 at 14:41
  • @NicoVanBelle the thing is, I really don't want to remove "@PostConstruct" as it is a part of some old integration with outside application - I added the ScopedService. but I will try if nothing else would work, thanks – majki Dec 13 '17 at 14:43
  • @daniu I added the AutowiredService in the original question – majki Dec 13 '17 at 14:46
  • @Maki You don't change the logic at all as it does exactly the same. `@PostConstruct` is a JEE standard, InitializingBean is Spring-only. So it's safe to replace one over the other unless you mix them (which you don't) AND the order of execution is important – Nico Van Belle Dec 13 '17 at 14:53
  • You did leave out the `dosomethingElse()` method and `RestOperations` which might be using the scopedService . Anyway, you say "It seems, that because of this @PostConstruct method, Spring checks ALL services" but a RequestScope bean is only created at request time, so you must have a place in the autowiring chain where it gets used or Spring wouldn't check. – daniu Dec 13 '17 at 14:54
  • @NicoVanBelle ok, thanks, will try – majki Dec 13 '17 at 14:54
  • @daniu I get it. It is just my assumption - it really doesn't make sense to me, that Spring would check something "just because", but as I wrote: "it seems" - it is weird, I agree. As for the RestOperations it is a Spring interface org.springframework.web.client.RestOperations, i will add the method in post in a moment – majki Dec 13 '17 at 15:03
  • @majki, there is but one RestOperations implementation and it is Spring's `RestTemplate` so inject that one as everybody does.. – Nico Van Belle Dec 13 '17 at 15:06

0 Answers0