This article summarizes the bean life cycle. It's a rather internal story. The following keywords are assumed to be known.
By the way, I took the Spring Professional v5.0 Exam sponsored by pivotal the other day, so this is a summary of what I learned at that time.
The life cycle of a bean is roughly divided into three.
Mainly in this phase
--Read / rewrite bean definition --Bean generation & DI --Initialization process
to hold. This phase is the most complex. The general flow is like this
Let's take a closer look.
First, the information required to generate the bean is read.
--Java Config with @Configuration
--Classes with @Component
, @Controller
, @ RestController
, @Service
, @Repository
--XML file with Bean definition
Based on the information read here, something like a Bean definition information list is created. (The entity is BeanDefinition ) Map of the object?) Bean implementation class, scope, dependent beans, fields, etc. are written in the bean definition information list.
Class | Name | Scope | Depends on | Property | ... |
---|---|---|---|---|---|
com.example.hoge.AImpl | a | Singleton | b | url=${url} | ... |
com.example.fuga.BImpl | b | Prototype | c | age=10 | ... |
com.example.piyo.CImpl | c | Singleton | ... |
Here, the bean definition information is rewritten.
It is an image that the Bean definition information list created in the previous step is modified.
For example, the process of embedding a property value in a placeholder declared with @Value
is performed here.
AImpl.java
@Component("a")
public class AImpl implements A {
@Value("${url}")
private String url;
}
application.properties
url=http://www.sample.com
Actually, BeanDefinition is modified based on the property value injected by @Value
.
BeanFactoryPostProcessor realizes rewriting of bean definition information. factory / config / BeanFactoryPostProcessor.java).
Processing is performed by the class that implements the BeanFactoryPostProcessor interface.
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory);
}
PropertySourcesPlaceholderConfigurer that implements BeanFactoryPostProcessor for the process of embedding property value with @Value
/springframework/context/support/PropertySourcesPlaceholderConfigurer.java) Class is responsible. (Refer to the link for detailed processing)
By the way, when using @Value
, it is necessary to define a bean that returns PropertySourcesPlaceholderConfigurer. (It seems that it is not necessary to explicitly define it if it is Spring Boot and Spring 4.3 or later)
This bean must be defined in a static method because Spring executes it before the bean is created.
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
At this point, the generation of Bean definition information is complete. Actually, the bean has not been generated yet. Beans are generated from the next phase.
At this point, a bean instance is finally created and DI (Dependency Injection) is performed. DI is performed in the following order.
Initialization processing is performed after bean generation.
As a feature of the processing that can be performed here, the initialization processing can be performed using the generated Bean.
For example, the processing of the method with @PostConstruct
is performed at this stage.
In the method with @PostConstruct
, you can write the initialization process using the injected field.
@Component
public class HogeServiceImpl implements HogeService {
private final Fuga fuga;
@Autowired
public HogeServiceImpl(Fuga fuga) {
this.fuga = fuga;
}
//Called after DI is over
//Return value must be void, no argument
@PostConstruct
public void populateCache() {
...
}
}
Pre-processing and post-processing can be inserted before and after the initialization processing of this step. This process is BeanPostProcessor The class that implements the interface does it.
public interface BeanPostProcessor {
//Preprocessing
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//Post-processing
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
This is the phase in which the bean is actually used.
ApplicationContext context = SpringApplication.run(AppConfig.class);
HogeService service = context.getBean("hogeService", HogeService.class); //Get Bean
service.do(); //Use of beans
This is the phase in which the DI container is destroyed.
Processing is performed before destroying the DI container.
Methods with @PreDestroy
added are processed at this stage.
@Component
public class HogeServiceImpl implements HogeService {
//Called before the DI container is destroyed
//Return value must be void, no argument
@PreDestroy
public void clearCache() {
...
}
}
When the close method of ConfigurableApplicationContext is called The DI container is destroyed.
context.close();
If generated by SpringApplication.run ()
, it hooks to the JVM shutdown and destroys the DI container.
ConfigurableApplicationContext context = SpringApplication.run(AppConfig.class);
//ShutdownHook is registered in the JVM