spring bean生命周期_Spring中Bean的生命周期

40770a933437d61925946ac136b9216e.png

    Spring从一个Bean定义变成容器中可以使用的Bean实例的过程,称为Spring中Bean的生命周期,Spring的Bean定义可以参考上篇文章《深入理解Spring中的Bean定义》。本篇文章将结合Spring初始化过程中的部分源码介绍如何从一个Bean定义变成一个可以使用的Bean实例。

    从Bean定义变为可用的Bean实例的主要步骤如下图所示:

2a229f01b0c91bf2f827cb609c38dc37.png

    上图中介绍了从Bean定义注册中心拿到一个Bean定义之后,是如何变为一个可以使用的Bean的关键步骤。其中和Bean的生命周期有关的重要步骤为如下的几步:

一、Bean实例化     bean的实例化,调用的是AbstractAutowireCapableBeanFactory工厂类的createBeanInstance方法,其核心源码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 解析Bean的class类型
        Class> beanClass = resolveBeanClass(mbd, beanName);
        // 如果Bean不是public,而且是不允许共有权限访问,直接抛出异常.
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw exception; // 省略异常...
        }
        /**
         * 通过指定的回调方法去创建bean实例,Spring5.0版本之后新增的方法。
         * 创建完成之后,会在初始化的时候指定bean的属性值转换器。即:ConversionService
         */
        Supplier> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }
        /**
         * 如果当前bean指定了对应的工厂方法,则通过工厂方法去创建bean实例
         *   底层会获取工厂方法【静态工厂方法|实例化方法】--> 然后解析方法入参 --> 然后执行反射调用创建实例 --> 封装为包装对象返回.
         */
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    /** 表示构造函数的参数是否已经解析妥当 */
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        if (resolved) {
            /** 如果构造函数的参数已经解析妥当 */
            if (autowireNecessary) {
                /** 则通过构造函数完成实例的创建 */
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                /**
                 * 使用默认的bean对象创建策略进行bean对象的创建
                 *  【设计模式:策略设计模式】
                 */
                return instantiateBean(beanName, mbd);
            }
        }
        /** 推断构造方法,获取候选的用来创建bean对象的构造函数 */
        Constructor>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        // 获取到了构造函数 || 注入模式为使用构造函数 || bean定义中指定了带参数的构造函数 || 创建bean对象时的入参args[参数列表对应的值列表]不为null
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            // 使用构造函数及入参进行bean对象的创建
            return autowireConstructor(beanName, mbd, ctors, args);
        }
        /** 获取指定的用来创建bean对象的默认构造函数 */
        ctors = mbd.getPreferredConstructors();
        if (ctors != null) {
            return autowireConstructor(beanName, mbd, ctors, null);
        }
        /**
         * 如果上述情况都没有:没有创建bean的回调方法 && 没有工厂方法 && 构造函数的参数未解析完毕 && 没有预先指定的默认构造函数
         *   则使用默认策略来创建bean对象
         */
        return instantiateBean(beanName, mbd);
 }

    从代码中可以看到,Bean实例的创建过程也并不是直接使用构造方法new出来这么简单。在Spring中,创建实例的方法常用有三种:构造方法、工厂方法和工厂Bean。而构造方法中又可能存在着多个重载的构造方法,具体使用哪一个,在该方法中会有一个推断过程,根据入参参数去反射调用参数列表相同的构造方法;如果使用工厂方法,则也会根据参数列表去调用特定的工厂方法;如果使用工厂Bean的方法,即:要创建的Bean实现了FactoryBean接口,则在此处会回调FactoryBean的getObject方法去创建Bean实例。通常在中间件开发中,会使用到该接口去创建一些定制化的Bean。

二、预解析注解元数据     在项目中,常用的注解例如:@Autowired,@Resource,@Required,@PostConstruct、@Scheduled等会在此处通过容器中默认的后置处理器去进行预解析,然后放入到元数据缓存中,在后期进行依赖注入的时候,会使用到该元数据信息去完成依赖关系确定以及依赖注入。此处主要有如下几个可能会执行的后置处理器:

3.1 AutowiredAnnotationBeanPostProcessor

    主要用来解析@Autowired和@Inject注解元数据。

3.2 CommonAnnotationBeanPostProcessor

    主要用来解析@Resource注解元数据。

3.3 RequiredAnnotationBeanPostProcessor

    主要用来解析@Required注解元数据。

3.4 InitDestroyAnnotationBeanPostProcessor

    主要用来解析@PreDestroy和@PostConstruct注解元数据。该注解是用来标注方法的,但是标注的方法此处并不会执行。

3.5 ScheduledAnnotationBeanPostProcessor

    如果项目中开启了任务调度,则该后置处理器会去解析@Scheduled注解元数据。

    该过程调用的是AbstractAutowireCapaleBeanFactory工厂类中的applyMergedBeanDefinitionPostProcessors方法,主要核心源码如下:

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class> beanType, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
}
    上述的5个主要接口都是实现了MergedBeanDefinitionPostProcessor接口的postProcessMergedBeanDefinition方法,在此处会被回调,也是Spring留给开发人员的一个扩展点,在Bean对象实例化之后执行一些自定义的处理逻辑。 三、暴露早期Bean对象

    什么是早期对象?

    即Spring中的earlySingleton。之所以称为早期对象,是因为这个对象并不是一个可以使用的Bean,因为Bean创建至该步骤之后,仅仅是一个对象,它所依赖的属性还并不具备值。

    早期对象是干什么用的?

    早期对象主要是来解决Spring中的循环依赖而引入的一种对象,这种对象通过提前将自己暴露到容器中,使得其他依赖该对象的Bean可以顺利完成初始化操作。具体是如何解决的,期待下篇文章。

四、属性填充     属性填充其实指的就是完成Bean对象中对其他对象属性的依赖注入。例如:UserService中有一个UserDao的属性,此处就是完成将UserDao作为UserService的属性注入到UserService中。     在注入之前,会先根据bean定义中指定的注入方式【即:通过名称注入(by-name)还是根据类型(by-type)注入】去容器中寻找依赖的Bean。如果未找到依赖的Bean,则会先去解决依赖,例如:UserService中有一个UserDao的属性,则会先去获取UserDao对应的Bean,如果没有,则会先去创建UserDao对应的Bean。创建完成之后,通过反射给对象完成属性赋值操作。 五、初始化     上述过程完成之后,对应的Bean对象已经拥有了属性值。此时如果Bean存在着一些实例化之后的自定义操作,例如:回调Aware方法,执行初始化方法(init-method),执行InitializingBean的后置处理方法、执行Bean自己的后置处理器方法等,这个过程就是Bean的初始化过程。当然执行这些初始化过程的方法是需要满足一定条件的,例如要执行Aware方法,就需要对应的Bean实现了相应的Aware接口,如果要执行init-method方法就需要Bean中存在init-method。初始化过程中调用的是 AbstractAutowireCapa -b l e BeanFactory 类的 initial izeBean方法,核心源码下:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction) () -> {
                invokeAwareMethods(beanName, bean);return null;
            }, getAccessControlContext());
        }else {/**
             * 调用Bean实现的Aware接口的方法,主要包括下面三个接口
             * BeanNameAware ----> setBeanName()
             * BeanClassLoaderAware ----> setBeanClassLoader()
             * BeanFactoryAware  ----> setBeanFactory()
             */
            invokeAwareMethods(beanName, bean);
        }
        Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {/** 调用Bean对象的postProcessBeforeInitialization方法,此处会执行标注@PostConstruct注解的方法 */
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }try {/**
             * 执行Bean的初始化方法:
             *
             * 1.先判断Bean是否实现了InitializingBean接口,如果实现了InitializingBean接口,则调用Bean对象的afterPropertiesSet方法;
             * 2.然后判断Bean是否有指定init-method方法,如果指定了init-method方法,则调用bean对象的init-method指定的方法.
             */
            invokeInitMethods(beanName, wrappedBean, mbd);
        }catch (Throwable ex) {throw ex;// 抛异常简写.
        }if (mbd == null || !mbd.isSynthetic()) {/**
             * 调用Bean对象的postProcessAfterInitialization方法
             *
             * 如果需要创建代理,在该步骤中执行postProcessAfterInitialization方法的时候会去创建代理
             * 调用AbstractAutoProxyCreator类的postProcessAfterInitialization方法,然后调用wrapIfNecessary方法去创建代理.
             *
             *
             * 另外还有一些Aware接口,也会在该步骤中执行,例如:ApplicationContextAwareProcessor后置处理器,对应的setApplicationContext方法会被执行.
             */
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }return wrappedBean;
}

5.1、initAwareMethod方法

    该方法即用来完成Aware接口的回调,核心源码如下:

private void invokeAwareMethods(final String beanName, final Object bean) {
        // 如果Bean实现了Aware接口
        if (bean instanceof Aware) {
            // 如果实现了BeanNameAware接口,则调用Bean的setBeanName方法
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            // 如果实现了BeanClassLoaderAware接口,则调用Bean的setBeanClassLoader方法
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            // 如果实现了BeanFactoryAware接口,则调用Bean的setBeanFactory方法
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
}

5.2、applyBeanPostProcessorsBeforeInitialization方法

    如果对应的Bean实现了BeanPostProcessor接口,则此处会回调Bean实例对应的postProcessBeforeInitialization方法,常用的@PostConstruct注解的执行就在该步骤中完成。执行@PostConstruct标注的方法对应的后置处理器为InitDestroyAnnotationBeanPostProcessor。对应的后置处理器方法核心源码如下:

@Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        /** 查找与Bean的生命周期相关的注解元数据 */
        LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
        try {
            /** 反射执行标注@PostConstruct注解的方法 */
            metadata.invokeInitMethods(bean, beanName);
        }
        catch (InvocationTargetException ex) {
            throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
        }
        return bean;
 }

5.3、invokeInitMethods方法

    该方法就是用来执行Bean的初始化方法的,此处的初始化方法主要包括两个。如果Bean实现了InitializingBean接口,此处会回调对应的afterPropertiesSet方法。如果在Bean中通过init-method指定了初始化方法,则还会调用init-method指定的初始化方法。该过程调用的是AbstractAutowireCapableBeanFactory的invokeInitMethods方法,其核心源码如下:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {
        // 判断bean对象是否为InitializingBean的实例
        // 如果实现了InitializingBean接口,则只掉调用bean的afterPropertiesSet方法
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
                ((InitializingBean) bean).afterPropertiesSet();
        }
        // 判断是否指定了init-method方法,如果指定了init-method方法,而且初始化方法不是afterPropertiesSet
        //  则通过反射执行指定的初始化方法。就是为了init-method也指定afterPropertiesSet而导致重复执行
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // 调用init-method方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
}

5.4、applyBeanPostProcessorsAfterInitialization方法

    执行Bean的后置处理方法,如果Bean实现了BeanPostProcessor接口,则此处会回调BeanPostProcessor接口的postProcessAfterInitialization方法。常见的如生成AOP代理对象就在该步骤中完成。生成代理对象使用的后置处理器为AbstractAutoProxyCreator,核心源码如下:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 创建代理对象
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
}

    在后置处理器中调用wrapIfNecessary方法完成代理对象创建。wrapIfNessary中会根据增强点使用Jdk动态代理或者Cglib动态代理技术去创建增强之后的代理对象。具体代码可以参考AbstractAutoProxyCreator中的wrapIfNecessary方法。

六、注册销毁

    上述过程执行完之后,这个Bean已经可以投入使用了,此时将要把创建好的Bean加入到单实例缓存池中。在被加入单实例缓存池之前,还需要判断其在容器关闭的时候是否需要执行销毁逻辑,该逻辑的源码位于AbstractBeanFactory类的registerDisposableBeanIfNecessary方法中,核心代码如下:

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
        // 如果不是多例的 && 需要被销毁
        if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
            // 如果是单实例Bean
            if (mbd.isSingleton()) {
                // 如果当前的bean不是空Bean && (存在着销毁方法 || (实现了DestructionAwareBeanPostProcessor接口 && requiresDestruction后置方法返回值为true))
                // 如果存在着(销毁方法 || 需要被销毁) && 是单例Bean   则会将当前的bean保存到一个disposableBeans对应的Map集合中,map的key为bean名称,value为要被销毁的bean
                registerDisposableBean(beanName,
                        new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
            }
            else {
                // 除了prototype之外其他作用域的Bean,则注册自定义的bean销毁回调方法
                Scope scope = this.scopes.get(mbd.getScope());
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
                }
                scope.registerDestructionCallback(beanName,
                        new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
            }
        }
    }

     上述注册逻辑中的requiresDestruction方法的核心源码如下:

protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
        return (bean.getClass() != NullBean.class &&  // 不是NullBean
                (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || // 存在着销毁方法,实现了DisposableBean接口或者Autocloseable接口
                // 实现了DestructionAwareBeanPostProcessor,而且对应的requiresDestruction方法返回了true【Spring的一个扩展点,可以自定义是否需要销毁】
                 (hasDestructionAwareBeanPostProcessors()
                  && DisposableBeanAdapter.hasApplicableProcessors(bean, getBeanPostProcessors()))));
    }

    那么如何判断当前bean中是否存在着销毁方法呢?通过DisposableBeanAdapter类的hasDestroyMethod方法来判断,核心源码如下:

public static boolean hasDestroyMethod(Object bean, RootBeanDefinition beanDefinition) {
        // bean实现了DisposableBean接口或者AutoCloseable接口
        if (bean instanceof DisposableBean || bean instanceof AutoCloseable) {
            return true;
        }
        // 存在着(inferred)方法【注意:一般如果未配置,默认的destroyMethod名称就是这个】,而且bean定义对应的class中存在着名称为close或者shutdown的方法
        String destroyMethodName = beanDefinition.getDestroyMethodName();
        if (AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {
            return (ClassUtils.hasMethod(bean.getClass(), CLOSE_METHOD_NAME) ||
                    ClassUtils.hasMethod(bean.getClass(), SHUTDOWN_METHOD_NAME));
        }
        return StringUtils.hasLength(destroyMethodName);
    }

    首先判断了是否实现了DesposableBean接口或者Autocloseable接口。如果实现了,那么肯定也会实现对应的销毁方法,即:destroy方法或者close方法。如果未实现,则会判断当前的bean中是否存在着名称为close或者shutdown的方法。如果存在,也会被当做需要被销毁的Bean放入到一个名称为disposableBeans的map集合中。map的key为Bean的名称,value为对应的Bean实例。

七、放入单实例缓存池

    Bean的生命周期过程执行完毕之后,此时Bean就是一个容器中可以使用的Bean。这个已经创建完成的Bean会被保存到Spring的单实例缓存池singletonObjects中。核心源码在DefaultSingletonBeanRegistry类的addSingleton方法中,如下所示:

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            /** 将创建好的单实例bean放入到单例缓存池中 */
            this.singletonObjects.put(beanName, singletonObject);
            /** 从三级缓存中删除 */
            this.singletonFactories.remove(beanName);
            /** 从二级缓存中删除(早期对象:已经实例化,但是未完成属性赋值的对象) */
            this.earlySingletonObjects.remove(beanName);
            /** 保存到已注册单实例Bean名称集合中 */
            this.registeredSingletons.add(beanName);
        }
    }

    至此,Spring的生命周期整个过程介绍完毕。这个过程中涉及到的更细节内容,后期文章会继续按照小点展开。例如:如何通过多级缓存解决Bean之间的循环依赖问题,如何推断构造方法,如果去选择默认的工厂方法等等。

关注菜鸟封神记,定期分享技术干货!

167c2484abc0d7d2a77b47aa373195d6.png

有收获的劳烦点个在看,然后帮转,感谢↓↓↓

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值