Is it able to inject RequestScope bean into Singleton bean using Constructor Injection in Spring?
Asked Answered
N

2

9

It is working as far as I tested. But I do not get it why and how it works.(Also I am not sure it is safe to use in production)

Here is my testCode

@Service
public class SomeService {

    private static final Logger logger = LoggerFactory.getLogger(SomeService.class);

    private final RequestContext requestContext; // @RequestScope + @Component Bean
    public SomeService(RequestContext requestContext) {
        this.requestContext = requestContext;
    }

    public void checkBean() {
        logger.info("Singleton Bean: {}, RequestScope Bean: {}", this, this.requestContext);
        String clientId = recommendContext.getClientId();
    }
}

The Scenario like below

  • Get a Request from Controller
  • SomeService is injected by Controller
  • Every request has its own RequestContext Bean
  • In Controller, call someService.checkBean()

The point I think strange is

  • SomeService is a singleton bean
  • RequestContext is declared as a final variable and only initiated by constructor
  • However it seems works.

The result of running code looks like below

2021-06-14 09:56:26.010 INFO  23075 --- [nio-8888-exec-1] p.service.SomeService   : Singleton Bean: pkgs.service.SomeServiceImpl@3c65ee26, RequestScope Bean: pkgs.context.RequestContext@56867592
2021-06-14 09:56:30.933 INFO  23075 --- [nio-8888-exec-3] p.service.SomeService   : Singleton Bean: pkgs.service.SomeServiceImpl@3c65ee26, RequestScope Bean: pkgs.context.RequestContext@73ddb7a4
2021-06-14 09:56:31.687 INFO  23075 --- [nio-8888-exec-4] p.service.SomeService   : Singleton Bean: pkgs.service.SomeServiceImpl@3c65ee26, RequestScope Bean: pkgs.context.RequestContext@56b4f7c8
2021-06-14 09:56:32.352 INFO  23075 --- [nio-8888-exec-5] p.service.SomeService   : Singleton Bean: pkgs.service.SomeServiceImpl@3c65ee26, RequestScope Bean: pkgs.context.RequestContext@33469287

As you can see Service is Single and RequestContext bean is unique for every request. I need some explanation of what is going on inside spring

Thanks

Nagel answered 14/6, 2021 at 1:13 Comment(0)
D
8

When a bean is request-scoped, Spring creates a proxy. Whenever this proxy is called, it delegates to an instance of the bean that is specific to the current request.

In your case, the RequestContext instance that is injected into SomeService and stored in the requestContext final variable is the proxy. If you tried to call the service outside the scope of a web request it would fail as the proxy would not be able to find the current request.

Deanadeanda answered 14/6, 2021 at 6:53 Comment(0)
I
0

You need to specify the proxy type in your bean definition ref: https://www.baeldung.com/spring-bean-scopes

@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
    return new HelloMessageGenerator();
}
Impenitent answered 19/6, 2023 at 14:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.