M01 Q05 What is the concept of a “container” and what is its lifecycle?
Container
The container is an execution environment which provides additional technical services for your code to use. Usually, containers use IoC technique, that allows you to focus on creating business aspect of the code, while technical aspects like communication details (HTTP, REST, SOAP) are provided by the execution environment.
All of these containers are implemented and you can just use it as a component, so you can add more business value to your product instead of focusing on the technical problems that are already solved.
In terms of Spring, it basically provides a container for the beans and it manages the lifecycle of the beans. So you need to focus on defining those beans or maybe defining some callbacks, etc and Spring will manage all of your beans. It will inject the required dependencies, it will call all of the callbacks, etc.
Spring Container Lifecycle
1. Application is started.
2. Spring container is created.
3. Containers read(load) configuration.
4. Beans definitions are created from the configuration.
5. The BeanFactoryPostProcessors are processing bean definitions. BeanFactoryPostProcessor is an interface. If you will implement it then you will get callbacks from the spring. And you will have a chance to process or somehow change the bean definitions.
6. Instances of Spring Beans are created.
7. Spring Beans are configured and assembled – resolve property values and inject dependencies.
8. The BeanPostProcessors are called before and after the initialization of the bean. So you have the ability to change the objects of the beans. In contrast to BeanFactoryPostProcessor which is working with the bean's definition andBeanPostProcessor is working with the object of the bean.
9. Application Runs.
10. The application gets shutdown.
11. Spring Context is closed.
12. Destruction callbacks are invoked.
Practice
Now let's look at the code and see how it is working in action.
Here is we have a Runner that has annotation config application context.
After the application starts the container will be created by the application context. And the application context will be supplied with the application configuration.
In the past, all of the definitions of the beans were in the XML. But now Spring supports annotation @Bean. And @ComponentScan will discover all beans with the annotation @Bean.
After discovering the beans the BeanFactoryPostProcessors will be called. ANd I have implemented my custom BeanFactoryPostProcessors because I want to show how it works into action. And it will just list the bean definitions that will be available for the post-processing.
After that, the constructors will be called from the Spring beans and instances will be created.
Then Spring will resolve all of the dependencies and will assemble bean.
And after having Bean assembled the bean BeanPostProcessor will be called. I also have a customBeanPostProcessor. I am logging at the moment just before the bean initialization and after bean initialization and also the bean name that was available for the processing.
After that application will run and then get shut down and destroyed methods will be called.
In my case, I don't have any additional logic.
Here you can see my SpringBean1 that has dependencies - SpringBean2, SpringBean3. And SpringBean1 is using setter injection. So instead of injecting through the constructor or injecting through the field directly, I am using setter injection because I want to log the moment when it happened.
And also I have init() method and destroyed() method.
Let's run and we can see the next output
So the first thing that happens is that the BeanFactoryPostProcessor is getting called. You can see all my beans and some other beans because the application context adds additional services for me.
After this gets called done the first is that the before and other initialization of application configuration is being called because the application configuration is also the bean.
Then Spring constructs or created the instance of the SpringBean1. And after creating the bean's instance goes to the second bean because SpringBean2 is a dependency of the first one.
So after the SpringBean1 gets constructed Spring tries to supply those dependencies. So it creates the SpringBean2 instance and it does the post-processing for the second bean. After the bean gets post-processed it gets injected and theSpringBean1is created and SpringBean1 is getting post-processed.
Then Spring injects SpringBean3.
And since Spring assembled SpringBean1 then the PostBeanProcessor on SpringBean1 gets called.
And after the next line of code, the trial of resources will close the application context. And all destroyed methods will be called.