An overview of the

Bean initialization learning, let’s first comb through the steps of Spring Bean initialization process

  1. 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

  1. 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
  1. 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:

  1. Usually we have a utility class in our projectApplicationContextUtilThrough theSpring AwareExtensions that can provide access to bean containersApplicationContextFinally, you can get the target Bean.
  2. 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

  1. Find all Disposable beans (beans that implement the DisposableBean interface)
  2. Iterate through each DisposableBean Bean
  3. Find the beans it depends on and remove them from the singleton pool.
  4. Call DisposableBean’s destroy() method
  5. 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