I want to create a UUID that is unique in a request life cycle. To do this, I create a UUID bean with the @Scope("request") annotation.
@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST)
public UUID requestUUID() {
return UUID.randomUUID();
}
I want to access this bean in my controller. So I inject it with @Autowired. This works fine.
@Controller
public class DashboardController {
@Autowired
UUID uuid;
@Autowired
WelcomeMessageService welcomeMessageService;
@Autowired
IssueNotificationService issueNotificationService;
@RequestMapping("/")
public String index(Model model) throws InterruptedException, ExecutionException {
System.out.println(uuid);
PortalUserDetails userLog = getPortalUserDetails();
BusinessObjectCollection<WelcomeMessage> welcomeMessages = welcomeMessageService.findWelcomeMessages(
20,
0,
userLog.getZenithUser(),
userLog.getConnectionGroup().getConnectionGroupCode(),
"FR");
if(welcomeMessages!=null) {
model.addAttribute("welcomeMessages", welcomeMessages.getItems());
}
BusinessObjectCollection<IssueNotification> issueNotifications =
issueNotificationService.findIssueNotifications(userLog.getZenithUser());
if(welcomeMessages!=null) {
model.addAttribute("welcomeMessages", welcomeMessages.getItems());
}
model.addAttribute("issueNotifications", issueNotifications);
return "index";
}
}
The controller call multiple services. Every service use a RestTemplate bean. In this RestTemplate bean, I want to get the UUID.
@Component
public class ZenithRestTemplate extends RestTemplate {
@Autowired
private UUID uuid;
public void buildRestTemplate() {
List restTemplateInterceptors = new ArrayList();
restTemplateInterceptors.add(new HeaderHttpRequestInterceptor("UUID", uuid.toString()));
this.setInterceptors(restTemplateInterceptors);
}
}
When I try to inject the UUID here, I have an error :
Error creating bean with name 'zenithRestTemplate': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.UUID com.geodis.rt.zenith.framework.webui.service.ZenithRestTemplate.uuid; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestUUID': 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.
What can I do to access my UUID bean inside the RestTemplate bean ?
My project use Spring-MVC, Spring-boot with java configuration.
I already tried to add a RequestContextListener but it doesn't solve the problem.
@Bean public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
To do this, I create a UUID bean with the @Scope("request") annotation. I want to access this bean in my controller. So I inject it with @Autowired. This works fine.
By default, Spring beans are singletons. The problem arises when we try to wire beans of different scopes. For example, a prototype bean into a singleton. This is known as the scoped bean injection problem.
Thus if you dependency-inject a prototype-scoped bean into a singleton-scoped bean, a new prototype bean is instantiated and then dependency-injected into the singleton bean. The prototype instance is the sole instance that is ever supplied to the singleton-scoped bean.
Using Lookup Method Essentially, Spring will override our annotated method and use our method's return type and parameters as arguments to BeanFactory#getBean. @Lookup is useful for: Injecting a prototype-scoped bean into a singleton bean (similar to Provider) Injecting dependencies procedurally.
I think you need to mark your UUID
request scoped bean like:
@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
Where controller is singleton
scoped bean you are injecting request
scoped bean in it. As singleton beans are injected only once per their lifetime you need to provide scoped beans as proxies which takes care of that.
Another option is to instead use the org.springframework.web.context.annotation.RequestScope
annotation:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_REQUEST)
public @interface RequestScope {
@AliasFor(annotation = Scope.class)
ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}
@RequestScope
is a meta-annotation on @Scope
that 1) sets the scope
to "request"
and 2) sets the proxyMode
to ScopedProxyMode.TARGET_CLASS
so you don't have to do it every time you want to define a request-scoped bean.
Edit:
Note that you may need to add @EnableAspectJAutoProxy
on your main configuration class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With