A single instance of 'application' scoped bean lives within a ServletContext instance. That means it can be used between multiple servlet based applications running in the same ServletContext, e.g. two Spring's ApplicationContexts can use the same 'application' scoped bean.
The default 'singleton' bean lives only within a single ApplicationContext, whereas, an 'application' bean lives within ServletContext i.e. across multiple ApplicationContexts.
Spring stores 'application' scoped bean as a regular ServletContext attribute.
Example
In this example we will create two web based ApplicationContexts running under same ServletContext .
WebApplicationInitializer
We are going to create two DispatcherServlets with different bean configurations and different mappings:
public class MyWebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerSpringContext(servletContext, MyWebConfig.class, "dispatcher1", "/app1/*");
registerSpringContext(servletContext, MyWebConfig2.class, "dispatcher2", "/app2/*");
}
private void registerSpringContext(ServletContext servletContext, Class<?> configClass,
String servletName, String mapping) {
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.register(configClass);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet =
servletContext.addServlet(servletName, new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping(mapping);
}
}
App1
@EnableWebMvc
@Configuration
public class MyWebConfig {
@Bean
public MyController myController() {
return new MyController();
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_APPLICATION)
public AppLevelPreference pref() {
return new AppLevelPreference();
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@Controller
public class MyController {
@Autowired
private AppLevelPreference appLevelPreference;
@GetMapping("/**")
public String appHandler(Model model, HttpServletRequest req) {
model.addAttribute("pref", appLevelPreference);
model.addAttribute("uri", req.getRequestURI());
model.addAttribute("msg", "response from app1");
return "app-page";
}
@PostMapping("/**")
public String appPostHandler(String fontSize, String background, HttpServletRequest req) {
appLevelPreference.setBackground(background);
appLevelPreference.setFontSize(fontSize);
System.out.println(req.getRequestURI());
return "redirect:" + req.getRequestURI();//redirect to GET
}
}
App2
@EnableWebMvc
@Configuration
public class MyWebConfig2 {
@Bean
public MyController2 myController2() {
return new MyController2();
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_APPLICATION)
public AppLevelPreference pref() {
return new AppLevelPreference();
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@Controller
public class MyController2 {
@Autowired
private AppLevelPreference appLevelPreference;
@GetMapping("/**")
public String appHandler(Model model, HttpServletRequest req) {
model.addAttribute("pref", appLevelPreference);
model.addAttribute("uri", req.getRequestURI());
model.addAttribute("msg", "response from app2");
return "app-page";
}
@PostMapping("/**")
public String appPostHandler(String fontSize, String background, HttpServletRequest req) {
appLevelPreference.setBackground(background);
appLevelPreference.setFontSize(fontSize);
System.out.println(req.getRequestURI());
return "redirect:" + req.getRequestURI();//redirect to GET
}
}
The application scoped bean
public class AppLevelPreference implements Serializable {
private String background = "#fff";
private String fontSize = "14px";
//getters/setters
.............
}
Note that both config classes MyWebConfig and MyWebConfig2 are using the same name for our application scoped bean (by naming same method name pref()), otherwise two different instances will be stored with two different ServletContext attribute names.
JSP page
src/main/webapp/WEB-INF/views/app-page.jsp<html>
<body style="background:${pref.background};font-size:${pref.fontSize}">
<h3>App</h3>
<form action="" method="post" >
Background <input type="text" name="background" value="${pref.background}"/>
Font size <input type="text" name="fontSize" value="${pref.fontSize}"/>
<input type="submit" value="Submit" />
<p>App content .... at ${uri}</p>
<p>${msg}</p>
</body>
</html>
Output
To try examples, run embedded tomcat (configured in pom.xml of example project below):
mvn tomcat7:run-war
Accessing http://localhost:8080/app1/
Now change the background value and submit the form:
Now access the other spring application at /app2/ :
Note that if you change the 'application' scope to the default 'singleton' scope in both config classes, then different AppLevelPreference instances will be used for each contexts.
Example ProjectDependencies and Technologies Used: - spring-webmvc 5.0.5.RELEASE: Spring Web MVC.
- javax.servlet-api 3.0.1 Java Servlet API
- JDK 1.8
- Maven 3.3.9
|