Beanのライフサイクル-初期化

前書き

初期化を制御する方法

        Beanの初期化フェーズでメソッドを指定できます。主に次のものがあります。

  • @PostContruct
  • InitializingBeanインターフェースを実装します(afterPropertiesSetメソッド)
  • @Bean(initMethod = "xxx")
  • BeanPostProcessorインターフェースを実装します(postProcessBeforeInitializationメソッド)

初期化メソッドの全体的なフロー

AnnotationConfigApplicationContext(コンテナの作成)
->
   refresh-> finishBeanFactoryInitialization-
      > preInstantiateSingletons-
        > getBean-
         > doGetBean-
           > createBean-
             > doCreateBean-
                > this.populateBean(beanName、mbd、instanceWrapper);(クラス属性の割り当て)
                     this.initializeBean(beanName、 ExposureObject、mbd);(BeanPostProcessor postProcessBeforeInstantiationおよびpostProcessAfterInstantiationの実行)

package com.example.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class TestInitConfig {
    @Bean(name = "myUser", initMethod = "initUser")
    Object userBean() {
        return new User();
    }

    public static class User implements InitializingBean, BeanPostProcessor
    {
        static {
            System.out.println("static");
        }

        User(){
            System.out.println("construct");
        }

        public void initUser() {
            System.out.println("initMethod");
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("InitializingBean");
        }

        @PostConstruct
        public void userPostConstruct() {
            System.out.println("PostConstruct");
        }

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeanPostProcessor==> " + "beanName:" + beanName);
            return bean;
        }
    }
}

結果:

static
construct
PostConstruct
InitializingBean
initMethod

@PostContruct

説明

コンストラクターを呼び出した後に実行するメソッドを指定します

原理

 

InitializingBeanインターフェース

説明

        初期化中に呼び出されるメソッドを指定します。これは、特定のBean用に構成できます。

        このメソッドは、Beanのすべての属性が初期化された後に呼び出されますが、SpringがBeanをlazy-initialized(lazy-init)(@ Lazyなど)に構成する場合、クラスオブジェクトが使用されていない場合、インスタンス化されません。 。クラスオブジェクトにより、InitializingBeanサブクラスのafterPropertiesSet()メソッドの実行に失敗します。Springコンテナーの起動時にafterPropertiesSet()メソッドを初期化して呼び出す必要がある場合は、アノテーション@Lazy(value = false)(org.springframework.context.annotation.Lazy)を使用して、遅延なしの読み込みとして構成できます。クラス。

原理

AbstractAutowireCapableBeanFactoryは、Bean初期化メソッドの呼び出しを完了します。

AbstractAutowireCapableBeanFactoryクラスのInvokeInitMethods


/**
 * Initialize the given bean instance, applying factory callbacks
 * as well as init methods and bean post processors.
 * <p>Called from {@link #createBean} for traditionally defined beans,
 * and from {@link #initializeBean} for existing bean instances.
 * @param beanName the bean name in the factory (for debugging purposes)
 * @param bean the new bean instance we may need to initialize
 * @param mbd the bean definition that the bean was created with
 * (can also be {@code null}, if given an existing bean instance)
 * @return the initialized bean instance (potentially wrapped)
 * @see BeanNameAware
 * @see BeanClassLoaderAware
 * @see BeanFactoryAware
 * @see #applyBeanPostProcessorsBeforeInitialization
 * @see #invokeInitMethods
 * @see #applyBeanPostProcessorsAfterInitialization
 */
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        // invokeAwareMethods方法为bean设置bean名称、类加载器、bean工厂
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        //通过责任链进行初始化前的处理
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        //调用初始化方法,afterPropertiesSet和初始化方法就在这个方法里
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        //通过责任链进行初始化后的处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

invokeInitMethodsを追跡します(AbstractAutowireCapableBeanFactoryにあります)

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
    //判断该bean是否实现了实现了InitializingBean接口,如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isDebugEnabled()) {
            logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }

        if (System.getSecurityManager() != null) {
            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                        //直接调用afterPropertiesSet
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                },getAccessControlContext());
            } catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }                
        else {
            //直接调用afterPropertiesSet
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        //判断是否指定了init-method方法,如果指定了init-method方法,则再调用制定的init-method
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            //进一步查看该方法的源码,可以发现init-method方法中指定的方法是通过反射实现
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

        上記のソースコードを分析すると、init-methodがリフレクションを介して実行され、afterPropertiesSetが直接実行されていることがわかります。したがって、afterPropertiesSetの実行効率はinit-methodよりも高くなります。

        Beanが非シングルトンとして定義されている場合、Beanの各インスタンスが作成されるときにafterPropertiesSetとinit-methodが実行されます。シングルトンBeanのafterPropertiesSetおよびinitメソッドは、Beanが初めてインスタンス化されたときに1回だけ呼び出されます。ほとんどの場合、afterPropertiesSetとinit-methodはシングルトンBeanに適用されます。

initMethod

説明

初期化中に呼び出されるメソッドを指定します。これは、特定のBean用に構成できます。

Springでは、init-methodがパラメーターなしのメソッドである必要があります。init-methodで指定されたメソッドにパラメーターがある場合、Springはjava.lang.NoSuchMethodExceptionをスローします。init-methodで指定されたメソッドは、public、protected、privateのいずれかであり、finalのメソッドでもあります。

原理

これは、上記の「InitializingBeanインターフェース」セクションで説明されています。

BeanPostProcessorインターフェース

その他のURL

Beanのライフサイクル--BeanPostProcessorアプリケーション

 

 

おすすめ

転載: blog.csdn.net/feiying0canglang/article/details/113905253