An overview of the
Bean initialization learning, let’s first comb through the steps of Spring Bean initialization process
- Source entrance AnnotationConfigApplicationContext# refresh ()
/ / execution BeanFactoryPostProcessors invokeBeanFactoryPostProcessors (the beanFactory); / / into the implementation (keyboard shortcut: CTRL + Alt + b) / / AbstractApplicationContext# invokeBeanFactoryPostProcessors / / 1. Method of execution BeanFactoryPostProcessors PostProcessorRegistrationDelegate. InvokeBeanFactoryPostProcessors (the beanFactory, getBeanFactoryPostProcessors());Copy the code
The creation process of Spring Beans
1. BeanDefinition Obtains the Bean definition information
- Define configuration class and scan path/scan package
// Define the configuration class and scan path/scan package
@Configuration
@ComponentScan("cn.edu.cqvie.service")
class AppConfig {
@Bean
public UserService userService200(a) {
return newUserService(); }}Copy the code
- Generate a BeanDefinition object entry structure to facilitate debugging
// Generate BeanDefinition object entryAnnotationConfigApplicationContext#refresh() -- AbstractApplicationContext#invokeBeanFactoryPostProcessors(..) ; -- PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(..) ; -- PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors(..) -- ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(..) -- processConfigBeanDefinitions(..) -- ConfigurationClassParser#parse(..) -- processConfigurationClass(..) -- doProcessConfigurationClass(..) -- ComponentScanAnnotationParser#parse(..) -- ClassPathBeanDefinitionScanner#doScan(..) -- findCandidateComponents(..) -- scanCandidateComponents(..)/ / scan package: Resource [] resources = getResourcePatternResolver () getResources (packageSearchPath); `
// Finally return Set
to generate BeanDefinition
Copy the code
-
Scan method scanCandidateComponents parsing 1). Scan the package to get the Resource array 2). Iterate over the Resource array and generate MetadataReader object using ASM module to get the meta information and annotation information on the class 3). Then through isCandidateComponent(..) Method to determine if the class file contains @Component information, or if it is a Bean. If it passes the check, it is added to the candidates and returned.
// Scan method
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
// Scan the class to get BeanDefinition
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
//MetadataReader contains MetadataReader for each class
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// Determine whether it is a Component
if (isCandidateComponent(metadataReader)) {
/ / by scanning @ BeanDefinition as ScannedGenericBeanDefinition Component
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
// Verify again that it is a Component
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: "+ resource); }}}else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: "+ resource); }}}catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: "+ resource, ex); }}else {
if (traceEnabled) {
logger.trace("Ignored because not readable: "+ resource); }}}}catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
Copy the code
2. Merger BeanDefinition
If a BeanDefinition has a parent BeanDefinition, then the merge takes place
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
Copy the code
3. The class is loaded
- If the current class is not lazily loaded and is a singleton Bean, we load the class
// Method entry
AbstractAutowireCapableBeanFactory#createBean(..) {
/ / load the classesClass<? > resolvedClass = resolveBeanClass(mbd, beanName); }Copy the code
- An implementation of the classloading method resolveBeanClass
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
if(System.getSecurityManager() ! =null) {
returnAccessController.doPrivileged((PrivilegedExceptionAction<Class<? >>) () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext()); }else {
return doResolveBeanClass(mbd, typesToMatch);
}
Copy the code
4. Instantiate the front method
Spring to allow third-party custom Bean creation way of expanding, can use InstantiationAwareBeanPostProcessors postProcessBeforeInstantiation to realize the Bean is created, The default creation process has been completed.
5. Infer the construction method
I’ll write the subsequent extensions separately
6. Instantiation
Gets an instance of a Bean through the constructor reflection
// Method entry
SimpleInstantiationStrategy#instantiate()
// Get the instance
return BeanUtils.instantiateClass(constructorToUse);
Copy the code
7. Post processing of BeanDefinition
BeanDefintion post-treatment method
// Method entry
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors(...)
Copy the code
Code that executes the BeanDefinition logic
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceofMergedBeanDefinitionPostProcessor) { MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp; bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName); }}Copy the code
8. Attribute padding
I’ll write the subsequent extensions separately
9. Aware execution
We often use the ApplicationContextAware main BeanNameAware, EmbeddedValueResolverAware, ApplicationContextAware, MessageSourceAware The one I personally use a lot is ApplicationContextAware. Here’s an example:
- Usually we have a utility class in our project
ApplicationContextUtil
Through theSpring Aware
Extensions that can provide access to bean containersApplicationContext
Finally, you can get the target Bean. - We can use the following method, code instance
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getApplicationContext(a) {
returncontext; }}// Call the method if UserServie has been registered
UserService userSerivce = ApplicationContextUtil.getApplicationContext().getBean(UserServie.class);
Copy the code
The logic of Aware is as follows:
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if(bcl ! =null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); }}if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); }}}Copy the code
10. Before initialization
It is important to note here in BeanPostProcessor postProcessBeforeInitialization method if returns null then follow-up rear Bean processors will not be executed.
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// bpp1 => bpp2 ==> bpp3
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Copy the code
11. The initialization
The initial method afterPropertiesSet() is called if the current Bean implements the InitializingBean interface.
((InitializingBean) bean).afterPropertiesSet();
Copy the code
12. After initialization
Bean after initialization, execution rear Bean processors postProcessAfterInitialization method
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
Copy the code
Bean destruction process
Now that we’ve covered Spring Bean initialization, let’s look at the Spring Bean destruction process. Since there are two patterns for beans: the singleton pattern and the prototype pattern, the prototype pattern is not managed by IOC and is collected by GC after being used. The singleton pattern is cached by the IOC container, so the life cycle of the created singleton instance Bean is the process of knowing that the IOC container is closed after it is created, so the core of Bean destruction is the closing process of the Bean container. We can close the container with the following code.
// Close the IOC container
applicationContext.close();
Copy the code
1. Close the container
Publish the ContextCloseEvnet event
3. Call the onClose method of LifecycleProcessor
4. Destroy the singleton Bean
- Find all Disposable beans (beans that implement the DisposableBean interface)
- Iterate through each DisposableBean Bean
- Find the beans it depends on and remove them from the singleton pool.
- Call DisposableBean’s destroy() method
- Locate the inner Beans currently contained in DisposableBean, and remove those beans from the singleton pool.
Initialize and destroy the extension method
The @PostConstruct and @PreDestroy annotations are primarily used to implement extension methods that are executed after the Bean is initialized and after the Bean is destroyed. For example, if I need to initialize a Bean and assign it to a static field, I can do this in @postConstruct mode. For example, if I need to close a socket session, I can do this at @preDestroy. Example code:
/** * Initialization method */
@PostConstruct
public void init(a) {
System.out.println("int invoke!");
}
/** * Method of destruction */
@PreDestroy
public void destroy(a) {
System.out.println("destroy invoke!");
}
Copy the code
Spring source parsing
- Spring Startup Process
- The life cycle of Spring Beans
- Spring Attribute Injection
- Spring loop dependencies
- Spring Aop
- Spring transactions
- Spring integration MyBatis
- Spring FAQ