General documentation: Article directory Github: github.com/black-ant

A. The preface

Let’s look at this picture again. It comes from @Topjava. Cn/article / 139…

Here are the first two steps:

  • Take stock of SpringIOC: Bean creation main process
  • Take stock of SpringIOC: attribute injection created by Bean

This article covers the process related to the next step InitializeBean. This article mainly includes:

  • InitializeBean Main process
  • Four initialization modes of the past life
  • Parameter summary after initializeBean

InitializeBean method

2.1 BeanInitializeBean method + initialization extension functionality

The main completed the Bean Bean creation creation, attribute injection, depend on the processing, from AbstractAutowireCapableBeanFactory # doCreateBean creation process, the process, the entity has been created


/** * Initiate the process and create the main process **/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
    / /...
    Object exposedObject = bean;
    try {
        populateBean(beanName, mbd, instanceWrapper);
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable ex) {
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
            throw (BeanCreationException) ex;
        } else {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); }}/ /...
}           

Copy the code

2.1.1 First is the loading process of InitializingBean

C173 - AbstractAutowireCapableBeanFactory M173_50 initializeBean - invokeAwareMethods (beanName, beans) : activate Aware method, For special bean processing - > PS: M173_50_02 - applyBeanPostProcessorsBeforeInitialization: after processor, before - invokeInitMethods: Activate users customize the init method - applyBeanPostProcessorsAfterInitialization: after processor, after M173_51 invokeAwareMethods - > PS: M173_51_01? - Set BeanName/BeanClassLoaderAware/BeanFactoryAware M173_52- according to the specific type of Aware applyBeanPostProcessorsBeforeInitialization ? - getBeanPostProcessor obtain all BeanPostProcessor and to call FOR loop postProcessBeforeInitialization? - If there is no Processor, return the original Object bean. There are returns the processed FOR - getBeanPostProcessor - processor. PostProcessBeforeInitialization (result, BeanName) M173_53- invokeInitMethods - If afterPropertiesSet is included, call ((InitializingBean) bean).AfterPropertiesSet ()/ / M173_50 code
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    // Activate the Aware method, which is handled separately depending on the permissions
    // Step 1: Get the system security interface and return a security manager if one has been set up for the current application
    if(System.getSecurityManager() ! =null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }else {
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }catch (Throwable ex) {
        .....
    }
    if (mbd == null| |! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean;
}   


Copy the code

PS:M173_50_02 Permission control

The AccessController. DoPrivileged: using the specified AccessControlContext enable and limiting permissions to perform the specified PrivilegedAction. PrivilegedAction: The Action used here that supports the execution of the logical getAccessControlContext with privileges enabled: Delegate the creation of an access control context to the SecurityContextProvider

Reason: The main reason for doing this is because the JVM’s mechanism for protecting domains is not accessible when using the SecurityManager. Java classes at this time. Security. The AccessController provides a default security policy enforcement mechanism, it USES a stack to check to determine potential unsafe operation is allowed, and use the doPrivileged code subject privilege

InitializeBean details

As you can probably see, there are a few important calls

  • invokeAwareMethods
  • applyBeanPostProcessorsBeforeInitialization
  • invokeInitMethods
  • applyBeanPostProcessorsAfterInitialization

We’ll look at these in more detail later:

2.2 invokeAwareMethods and Aware processing

This is for the implementation of the Aware method, and by the way, the Aware process

The Aware interface is the core interface of the Spring container, and it is a super interface with the function of identification. The beans implementing this interface have the ability to be notified by the Spring container

Usage: Indicates that a bean is entitled to be notified of a particular framework object structure by the Spring container via a callback-style method: normally it should contain only a method that takes a single argument and returns void: notifying the Spring container of its hidden properties

Common types of BeanAware

BeanNameAware: Set the beanName defined by the bean object to the current instance of the object. - BeanFactoryAware: The BeanFactory container will inject itself into the current object instance so that the current object will have a reference to the BeanFactory container.// Of course, Spring provides not just the three Aware interfaces above, but a series of:- LoadTimeWeaverAware: When loading Spring beans, weave in third-party modules such as AspectJ - BootstrapContextAware: Resource adapter BootstrapContext, such as JCA, CCI-ResourceloaderAware: Loader for the underlying access to the resource - PortletConfigAware: Portletconfig-portletcontextaware: portletContext-ServletConfigAware: ServletConfig-ServletContextaware: ServletContext - MessageSourceAware: internationalization - ApplicationEventPublisherAware: application events - NotificationPublisherAware: JMX notificationsCopy the code

There is one operation in the overall structure: check, activate Aware, what is the cause and effect of this process?

The system of Aware interfaces is huge, let’s just take BeanNameAware as an example

Structurally speaking, it’s just an interface

public interface BeanNameAware extends Aware {
	// Install as above, take a single argument and return void
	void setBeanName(String name);
}
Copy the code

So,BeanNameAware what did he do?

BeanNameAware is an interface implemented by a bean that wants to know the name of its bean in the bean factory, and the corresponding bean relies on the interface to get its BeanName

Be aware of, be aware of, be aware of

That is, classes that implement the corresponding Aware interface can only do the corresponding thing. That is, the Bean implements BeanNameAware, so it is aware of the BeanName the system generates for it

This is why the aware method is required to be void, in this case for the callback to get the set value.

At the bottom of the code, the entry point for Aware to run

C- AbstractAutowireCapableBeanFactory
	M- invokeAwareMethods(final String beanName, finalObject bean) ? - This method is called in initializeBeanprivate void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
    
        // Call the corresponding method based on the Aware type
        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

That is, after the various properties are processed, aware is part of the functionality that is completed through callbacks after the related methods are processed. For example, invokeAwareMethods handles three things:

  • BeanNameAware sets the Bean name
  • BeanClassLoaderAware set BeanClassLoader
  • BeanFactoryAware sets up the Bean factory

The realization of Aware

public class CommonService implements BeanNameAware {
    
    private String beanName;
    
    // Spring will call back to the interface after the name is generated and inject the BeanName into the interface so that the object is aware of it
    @Override
    public void setBeanName(String name) {
        this.beanName = name; }}Copy the code

2.4 applyBeanPostProcessorsBeforeInitialization

It makes sense here to execute BeanPostProcessors related methods

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}


/ / applyBeanPostProcessorsAfterInitialization similar, the difference is called postProcessAfterInitialization

Copy the code

2.5 invokeInitMethods Main process

At this point the properties are set, check to see if the bean implements InitializingBean or defines a custom init method, and if so, call the necessary callbacks

// PS:M173_51_01 Details processing
    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null| |! mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            // For the same reason, the methods with the security domain SecurityManager are called through the AccessController authorization
            if(System.getSecurityManager() ! =null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throwpae.getException(); }}else{ ((InitializingBean) bean).afterPropertiesSet(); }} /if(mbd ! =null&& bean.getClass() ! = NullBean.class) { String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&
                    // To avoid repeated calls! (isInitializingBean &&"afterPropertiesSet".equals(initMethodName)) && ! mbd.isExternallyManagedInitMethod(initMethodName)) {// Call the specified custom init method on the given beaninvokeCustomInitMethod(beanName, bean, mbd); }}}Copy the code

Supplement 1: InitializingBean method

> InitializingBean is an interface, m-AfterPropertiesSet () : | - in the initialization process of bean will determine whether the current bean implements InitializingBean | - if implemented with # afterPropertiesSet () method, Initialize work initialization processing | | - attributes - and then check whether also specifies the init method - | - if the specified by reflection mechanism to invoke the specified init - | - use of reflection mechanism, the execution method method to activate the user custom initialization methodCopy the code

Supplement 2: invokeCustomInitMethod

This is usually handled via the annotation specified by @bean (initMethod = “initMethod”)

  • Gets the initMethod to configure
  • Get the method object by reflection
  • Method is executed in the manner of method reflection
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
            throws Throwable {
        
        // Get the configured initMethod
        String initMethodName = mbd.getInitMethodName();
        
        // Get the method object by reflection
        Method initMethod = (mbd.isNonPublicAccessAllowed() ?
                BeanUtils.findMethod(bean.getClass(), initMethodName) :
                ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));

        // If the method does not exist, throw an exception or return
        if (initMethod == null) {
           // Indicates whether the configured init method is the default method
            if (mbd.isEnforceInitMethod()) {
                throw newBeanDefinitionValidationException(.....) ; }else {
                return; }}// If possible, determine the corresponding interface method for the given method handle
        Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);

        // Execute method in the same way as method reflection
        if(System.getSecurityManager() ! =null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                ReflectionUtils.makeAccessible(methodToInvoke);
                return null;
            });
            try {
                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
                        methodToInvoke.invoke(bean), getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                InvocationTargetException ex = (InvocationTargetException) pae.getException();
                throwex.getTargetException(); }}else {
            try {
                // Obtain the license after reflection
                ReflectionUtils.makeAccessible(methodToInvoke);
                methodToInvoke.invoke(bean);
            }
            catch (InvocationTargetException ex) {
                throwex.getTargetException(); }}}Copy the code

2.5 Invocation Methods of initialization Methods

There are several ways to initialize beans at application startup:

  • Implement InitializingBean interface method afterPropertiesSet
  • Implement the ApplicationRunner interface method run(ApplicationArguments args)
  • Method annotation @postConstruct
  • @bean (initMethod = “initMethod”) is specified via annotations
// The log is in order
- @PostConstruct
- InitializingBean 
- @Bean(initMethod = "initMethod")    
- ApplicationRunner
Copy the code

The loading process for @PostConstruct

@PostConstruct belongs to javax.annotation, which is one of the native Java annotations that must be called before the class is put into service for a method that needs to perform any initialization after dependency injection is complete. All classes that support dependency injection must support this annotation. Methods annotated with PostConstruct must be called even if the class does not request the injection of any resources.

C- DefaultInstanceManager # newInstance C- DefaultInstanceManager # populateAnnotationsCache C- DefaultInstanceManager #  findPostConstructCopy the code

@Bean(initMethod = “initMethod”)

As mentioned above, this is eventually executed in initializeBean -> invokeInitMethods, and finally by reflection

String initMethodName = mbd.getInitMethodName();

C- AbstractBeanDefinition
    F- private String initMethodName;
    
// Corresponding initialization process
C- ConfigurationClassBeanDefinitionReader
    M- loadBeanDefinitionsForBeanMethod

// Here we get the @bean property initMethod
// @Bean(initMethod = "initMethod", autowire = Autowire.BY_TYPE)
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
    beanDef.setInitMethodName(initMethodName);
}   

/ / the last call in AbstractAutowireCapableBeanFactory
C- AbstractAutowireCapableBeanFactory
    M- initializeBean
    M- invokeInitMethods 

Copy the code

afterPropertiesSet

AfterPropertiesSet is also executed in invokeInitMethods


    if(System.getSecurityManager() ! =null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }else {
        invokeAwareMethods(beanName, bean);
    }

Copy the code

Start process for ApplicationRunner # run

Execution of the run method is simpler. ApplicationRunner is a SpringBoot exclusive method that executes when SpringApplication calls the run method

public ConfigurableApplicationContext run(String... args) {
        / /...
        try {
            / /...
            // Execute the run method
            callRunners(context, applicationArguments);
        } catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }
         / /...
        return context;
}


private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    // Add the ApplicationRunner class
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    // Add the CommandLineRunner class
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    // All runners are processed
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceofCommandLineRunner) { callRunner((CommandLineRunner) runner, args); }}}// Finally pass (runner).run(args); call

Copy the code

conclusion

This one is relatively simple, but the overall effect is better than the last one. I feel that each piece should not be too long. If there are too many points involved, it is not easy to clear up.

Appendix:

Original object:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)

InitializeBean before entering the Object

In fact, property injection,autowired has already taken care of that

After processing, it will not be sent, because there is no aware and postProcess operation, in effect the same