Accessing Global ModelAttributes in Another Controller Advice in Spring
Problem: You're working on a Spring application and want to access data stored in a global Model
object from one controller advice in another controller advice. This can be useful for things like setting up global application state, user authentication, or logging information across the application.
Rephrased: Imagine you have a central storage space in your Spring application where you put information that needs to be available everywhere. You want to be able to access that storage from different parts of the application. This article will guide you on how to access this global storage using controller advice in Spring.
Scenario & Code:
Consider the following scenario:
- GlobalControllerAdvice.java:
@ControllerAdvice
public class GlobalControllerAdvice {
@ModelAttribute
public void setGlobalAttribute(Model model) {
model.addAttribute("globalKey", "Global Value");
}
}
- AnotherControllerAdvice.java:
@ControllerAdvice
public class AnotherControllerAdvice {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex, Model model) {
// Want to access "globalKey" from the model here
String globalValue = model.getAttribute("globalKey", String.class);
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
In this example, GlobalControllerAdvice
sets a global attribute "globalKey" with a value "Global Value". We want to access this value in the exception handler in AnotherControllerAdvice
. However, directly accessing model.getAttribute("globalKey")
in AnotherControllerAdvice
will return null
because model
is a new instance created for each request.
Solution & Insights:
To access global attributes in another controller advice, we need a shared storage mechanism. The easiest way is to use a singleton bean like ApplicationContext
. Here's how:
-
Inject ApplicationContext: Inject the
ApplicationContext
into yourAnotherControllerAdvice
:@ControllerAdvice public class AnotherControllerAdvice { @Autowired private ApplicationContext applicationContext; @ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception ex, Model model) { // Access global attribute from ApplicationContext String globalValue = applicationContext.getBean("globalKey", String.class); return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } }
-
Store and Retrieve Global Attributes: The
applicationContext
provides access to the entire Spring application context, allowing you to retrieve global attributes stored within it.-
In your
GlobalControllerAdvice
, instead of adding the attribute directly to theModel
, store it in theApplicationContext
:@ControllerAdvice public class GlobalControllerAdvice { @Autowired private ApplicationContext applicationContext; @ModelAttribute public void setGlobalAttribute() { applicationContext.getBeanFactory().registerSingleton("globalKey", "Global Value"); } }
-
In your
AnotherControllerAdvice
, retrieve the global attribute usingapplicationContext.getBean()
:@ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception ex, Model model) { String globalValue = applicationContext.getBean("globalKey", String.class); return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); }
-
Key Points:
- Model Scope: Remember that
Model
objects in Spring MVC are request-scoped, meaning each request gets a new instance. - ApplicationContext Scope: The
ApplicationContext
is a singleton, allowing you to store and retrieve global attributes across requests. - Alternatives: You can also consider using Spring's
Session
orApplication
scope for storing global data depending on your specific needs.
Benefits:
- Centralized data management: Global attributes allow you to share information across different parts of your application.
- Code Reusability: By accessing global attributes from controller advice, you can easily reuse the same information in multiple exception handlers or other aspects of your application.
- Simplified logic: You don't need to pass data around between controllers or services, as you can directly access it from the global context.
Additional Information:
- Spring's official documentation: https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-model-attributes
- Spring's
ApplicationContext
class: https://docs.spring.io/spring-framework/docs/current/javadoc/org/springframework/context/ApplicationContext.html
Conclusion:
By utilizing the ApplicationContext
, you can seamlessly access global attributes from different controller advice classes in your Spring application, simplifying your code and ensuring consistency in your application logic.