前書き
初期化を制御する方法
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