Before you read about this article, I think that you should reference to the previous article.
So, in this article, we will find out the inside part of the way @Configuration
annotation works.
Table of Contents
- How @Configuration annotation work
- Use MVC model in Java web application
- The difference between @Configuration and @Component
- Wrapping up
How @Configuration annotation work
Before going deeper it, we will glance at a little bit about declaration of @Configuration
at Spring MVC.
@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
@Component
public @interface Configuration
@Configuration
@PropertySource("classpath:application.properties")
@ComponentScan("com.manhpd.exspringmvc")
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter{
@Bean
public MyBean myBean() {
// instantiate, configure and return bean ...
return new MyBean();
}
}
According to the documentation of spring.io, @Configration
indicates that a class declares one or more Bean
methods and may be processed by the Spring container to generate bean definitions and service requests for those bean at runtime.
So, from this definition, we have two things that we need to mark:
@Configuration
annotation indicates that the class has@Bean
definition methods.- Spring container can process the class and generate Spring Beans to be used in the application. And beans are the objects that return from the above methods such as myBean().
Next, we have some questions:
- When does Bean objects create?
- After created, where will Bean objects be contained? and What is it?
- When will Bean objects be popped from something?
Now, we will answer each question:
-
First question - When does Bean objects create?
In Spring MVC, we have a segment code:
public class WebInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { // Create the root Spring application context AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(AppConfig.class); rootContext.setServletContext(servletContext); // Manage the lifecycle of the root application context servletContext.addListener(new ContextLoaderListener(rootContext)); // Create the dispatcher servlet's Spring application context AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); dispatcherContext.register(DispatcherConfig.class); // Register and map the dispatcher servlet ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext)); servlet.addMapping("/"); servlet.setLoadOnStartup(1); } }
We will see that we’re using the
onStartup()
function inWebApplicationInitializer
interface. An implementation of the WebApplicationInitializer interface configures the ServletContext programmatically. In particular, it allows for the creation, configuration, and registration of the DispatcherServlet programmatically. So, the web.xml file will be removed from modern Spring MVC applications.In Spring 3.1, the DispatcherServlet, in Servlet Container, had to be registered via web.xml file.
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>*.request</url-pattern> </servlet-mapping>
Back to your article,
onStartup
method will be called to initialize our application.AnnotationConfigWebApplicationContext implementation which accepts annotated classes as input - in particular
@Configuration
- annotated classes, but also plain@Component
classes.It allows for registering classes one by one (specifying class names as a config location) as well as for classpath scanning (specifying base package as config location).
So,
@Configuration
class is typically bootstrapped using AnnotationConfigWebApplicationContext.rootContext.register(AppConfig.class);
After registering
AppConfig.class
into AnnotationConfigWebApplicationContext, it will load all of Beans that is defined in@Configuration
class.Assumed that we have custom configurations that are spread across multiple classes, now, we want to use all of these configurations. Spring WebApplicationInitializer provides a way to specify root package to be scanned for configuration classes.
rootContext.setConfigLocation("com.manhpd.app.config");
The next step is to add
ContextLoaderListener
to theServletContext
which will be responsible to load the context.// Manage the lifecycle of the root application context servletContext.addListener(new ContextLoaderListener(rootContext));
The final step is creating and registering Dispatcher servlet, which is the entry point of our application.
// Register and map the dispatcher servlet ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext)); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/");
Therefore, Beans object will be created at the first time of an application. In Bean objects, we will set a scope for them, refer to the link.
-
Second question - Where will Bean objects be contained? and What is it?
From the above section 1, we see that Spring loads beans into AnnotationConfigWebApplicationContext before we have even requested it. This is to make sure all the beans are properly configured and application fail-fast if something goes wrong.
So, application context will contain all Bean objects.
ApplicationContext is one of the Spring container in Spring framework. It is the central interface within a Spring application for providing configuration information to the application. It is read-only at runtime, but can be reloaded if necessary and supported by the application.
Some derived class from ApplicationContext are:
-
AnnotationConfigApplicationContext: loads a Spring application context from one or more Java-based configuration classes.
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
-
AnnotationConfigWebApplicationContext: loads a Spring web application context from one or more Java-based configuration classes.
ApplicationContext context = new AnnotationConfigWebApplicationContext(WebAppConfig.class);
-
ClassPathXMLApplicationContext: Loads a context definition from one or more XML files located in the classpath.
ApplicationContext context = new ClassPathXMLApplicationContext("springConfig.xml");
-
FileSystemXMLApplicationContext: Loads a context definition from one or more XML files located in the filesystem.
ApplicationContext context = new FileSystemXMLApplicationContext("C:/springConfig.xml");
-
XMLWebApplicationContext: Loads a context definition from one or more XML files contained in the web application.
ApplicationContext context = new XMLWebApplicationContext("/WEB-INF/config/springConfig.xml");
-
-
Third question - When will Bean objects be popped from something?
This queston is easy to answer. You can reference to this link.
Use MVC model in Java web application
To notify for our project that use Spring MVC, we will use @EnableWebMvc
annotation in @Configuration
class.
@Retention(value=RUNTIME)
@Target(value=TYPE)
@Documented
@Import(value=DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc
It will import the Spring MVC configuration from WebMvcConfigurationSupport.
The difference between @Configuration and @Component
This part is refer from link.
Consider the below two code segments:
@Configuration
public static class Config {
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
@Component
public static class Config {
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
The first piece of code works fine. SimpleBeanConsumer
will get a link to singleton SimpleBean
.
The second piece of code is totally incorrect because Spring will create a singleton bean of SimpleBean
, but SimpleBeanConsumer
will obtain another instance of SimpleBean
which is out of the Spring context control.
If we use @Configuration
, all methods marked as @Bean
will be wrapped into a CGLIB wrapper which works as if it’s the first call of this method, then the original method’s body will be executed and the resulting object will be registered in the Spring context. All further calls just return the bean retrieved from the context.
In the second piece of code, new SimpleBeanConsumer(SimpleBean())
just calls a pure java method.
To fix this mistake in the second piece of code, we do:
@Component
public static class Config {
@Autowired
SimpleBean simpleBean;
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean);
}
}
Wrapping up
- Understanding why configuration in Spring MVC and some parts in framework.
@Configuration
annotation will wrap all@Bean
methods into CGLIB wrapper.
Refer:
https://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/index.html
https://blog.codeleak.pl/2013/11/controlleradvice-improvements-in-spring.html
https://blog.codeleak.pl/2014/09/using-configurationproperties-in-spring.html
https://blog.codeleak.pl/2013/04/spring-mvc-pathvariable-tips.html
The difference between @Configuration
and @Component
http://dimafeng.com/2015/08/29/spring-configuration_vs_component/
https://stackoverflow.com/questions/12704891/how-does-spring-3-1-java-based-configuration-work
https://www.journaldev.com/21033/spring-configuration-annotation
Use web.xml and WebApplicationInitializer class
https://www.javadevjournal.com/spring/spring-webapplicationinitializer/
https://spring.io/blog/2008/03/27/spring-java-configuration-what-s-new-in-m3/
@EnableWebMvc annotation https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html
WebApplicationContext
http://dimafeng.com/2015/07/22/web-app-context/
CGLIB https://stackoverflow.com/questions/38089200/what-is-cglib-in-spring-framework