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, exposedObject, 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进行配置。

扫描二维码关注公众号,回复: 12807766 查看本文章

        该方法在Bean的所有属性初始化完成后调用,但是当Spring 配置bean为延迟初始化(懒加载(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被定义为非单例的,那么afterPropertiesSet和init-method在bean的每一个实例被创建时都会执行。单例 bean的afterPropertiesSet和init-method只在bean第一次被实例时调用一次。大多数情况下 afterPropertiesSet和init-method都应用在单例的bean上。

initMethod

说明

指定初始化时调用的方法,可以针对某个具体的bean进行配置。

Spring要求init-method是一个无参数的方法,如果init-method指定的方法中有参数,那么Spring将会抛出java.lang.NoSuchMethodException。init-method指定的方法可以是public、protected以及private的,并且方法也可以是final的。

原理

在上边“InitializingBean接口”部分已经说过。

BeanPostProcessor接口

其他网址

Bean生命周期--BeanPostProcessor应用_feiying0canglang的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/feiying0canglang/article/details/113905253
今日推荐