Spring extension interface InitializingBean

Directory

1. Environment

Two, examples

2.1. Description

3. Execution process

3.1 Source code analysis


One, environment

  • jdk: 1.8
  • spring-boot: 2.7.1

Second, Example

@Component
public class TestInit implements InitializingBean {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("call TestInit.afterPropertiesSet method");
    }
}

operation result:

2.1, Description

  • springboot provides the InitializingBean interface, which users can implement to customize initialization operations
  • Implement the InitializingBean interface to rewrite the afterPropertiesSet method and register it in the spring container. After the instance is created, it can trigger the execution of the custom initialization operation

3. Execution process

I have been curious and want to figure out when to call the extension point afterPropertiesSet() method? How to call it?

To satisfy curiosity, start a simple springboot project to track the source code execution process as follows:

3.1 Source Code Analysis

1. Springboot project startup entry SpringApplication.run

public ConfigurableApplicationContext run(String... args) {
        // record start time
long startTime = System. nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
        // Prepare the ApplicationContext
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
        // Get the listener from spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
        // publish event
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // Environmental parameters
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            // Configure settings into system parameters
configureIgnoreBeanInfo(environment);
            // output banner
Banner printedBanner = printBanner(environment);
            // Create applicationContext IOC container
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
            // Prepare the context IOC container, set a series of attribute values
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            // Line 308, start the spring container
refreshContext(context);
            // processing after refresh
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this. logStartupInfo) {
new StartupInfoLogger(this. mainApplicationClass). logStarted(getApplicationLog(), timeTakenToStartup);
}
            // publish event
listeners.started(context, timeTakenToStartup);
            // Call the runner, which implements the interface of ApplicationRunner or CommandLineRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}

Here focus on adjusting refreshContext(context) to start the container

2. SpringApplication.refreshContext starts the container

protected void refresh(ConfigurableApplicationContext applicationContext) {
        // 734 lines
applicationContext. refresh();
}

Then call AbstractApplicationContext.refresh() to start the Spring container

3. AbstractApplicationContext.refresh() starts the Spring container

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

        // Prepare before starting the container. Startup time, status and environment, etc.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare to use the bean factory in the context
        prepareBeanFactory(beanFactory);

        try {
            // Allows postprocessing of bean factories in context subclasses.
            postProcessBeanFactory(beanFactory);

            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            // call the factory handler registered as a bean in the context
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register the bean handler that intercepts bean creation.
            registerBeanPostProcessors(beanFactory);
            beanPostProcess. end();

            // Initialize the message source for this context.
            initMessageSource();

            // Initialize the event broadcaster
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // register event listener
            registerListeners();

            // Line 583, instantiate all remaining (non lazy-init) singletons
            finishBeanFactoryInitialization(beanFactory);

            // Complete the boot operation
            finishRefresh();
        }

        catch (BeansException ex) {
           ...
        }

        finally {
            resetCommonCaches();
            contextRefresh.end();
        }
    }
}

Lists the entire process of Spring container startup. This example focuses on the InitializingBean extension point, and other content will not be explained in detail. Instantiate all remaining (non lazy-init) singletons finishBeanFactoryInitialization(beanFactory);

4. AbstractApplicationContext.finishBeanFactoryInitialization(…) initialization (non-lazy-init) singleton

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ...

    // Line 918, instantiate all remaining (non lazy-init) singletons.
    beanFactory. preInstantiateSingletons();
}

Call the preInstantiateSingletons method of the bean factory class to instantiate the bean

5. ConfigurableListableBeanFactory.preInstantiateSingletons() instantiates beans

@Override
public void preInstantiateSingletons() throws BeansException {
    ...

    // Line 955, get bean
    getBean(beanName);

    ...
}

Here the bean is obtained by adjusting the parent class AbstractBeanFactory.getBean

6.AbstractBeanFactory.getBean(beanName) gets bean

public Object getBean(String name) throws BeansException {
    // line 208
    return doGetBean(name, null, null, false);
}

Then call the doGetBean(…) method of this class to get the bean

7. AbstractBeanFactory.doGetBean gets bean

protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {
        ...
            // Line 332, create a bean instance
            if (mbd. isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        ...
                    }
                });
                ...
            }

        ...
    }

    return adaptBeanInstance(name, beanInstance, requiredType);
}

Then tune the createBean of the subclass to create an instance

8.AbstractAutowireCapableBeanFactory.createBean(…) creates an instance

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
    ...
    //line 542
    doCreateBean(beanName, mbdToUse, args);
    ...
}

Call this class doCreateBean

9.AbstractAutowireCapableBeanFactory.doCreateBean(…) executes creating beans

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    ...
    // instantiate the bean
    // Solve the problem of circular dependency, whether circular dependency is allowed, etc.
    ...
        // Attribute assembly, that is, automatic injection
        populateBean(beanName, mbd, instanceWrapper);

        // Line 620, application factory callbacks and initialization methods and bean post-handlers.
        // such as init-method, InitializingBean interface, BeanPostProcessor interface
        exposedObject = initializeBean(beanName, exposedObject, mbd);
   ...
}

10. AbstractAutowireCapableBeanFactory.initializeBean processing initialization completed processing

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    ...
        // method callback
        invokeInitMethods(beanName, wrappedBean, mbd);
    ...
}

11. Method callback processing of AbstractAutowireCapableBeanFactory.invokeInitMethods instance

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    // It is judged as the implementation class of InitializingBean, and the afterPropertiesSet method is rewritten, then the afterPropertiesSet method is called
    if (isInitializingBean & amp; & amp; (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
        ...
        ((InitializingBean) bean). afterPropertiesSet();
        ...
    }
    ...
}

At this point, the implementation and triggering time of the InitializingBean extension point is over.

ps: The above is a summary of reading the source code and reading a lot of literature. If there are any mistakes or deficiencies, please point them out and leave a message for exchange. I will continue to work hard to learn and share more content with dry goods.