美文网首页
spring容器之创建bean的终结篇

spring容器之创建bean的终结篇

作者: 会上树的程序猿 | 来源:发表于2019-07-23 23:30 被阅读0次

    关于bean的创建篇章,本节是终结篇,也是我们对#doCreateBean(...)方法的最后一个过程的详细分析,即初始化bean,这里的bean是我们最终想要的bean,直接看代码:

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                //1.激活Aware,对特殊的bean进行处理,比如:Aware BeanClassLoaderAware BeanFactoryAware
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            //同上
            invokeAwareMethods(beanName, bean);
        }
    
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            //2.应用前置处理器
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
    
        try {
            //3.激活用户自定义的init方法
            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()) {
            //4.应用后置处理器
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
    
        return wrappedBean;
    }
    

    上述就是初始化bean的过程,简单的来小结一下流程:

      1. 激活Aware方法
    • 2.前置处理器的应用
    • 3.激活用户自定义的方法
      1. 后置处理器的应用

    我们分别来看上述的这四个流程

    激活Aware方法

    我们先来了解下什么是Aware,Aware是感知的意思,在spring中提供了一些Aware相关的接口,如:BeanFactoryAware ApplicationContextAware ResourceLoaderAware ServletContextAware BeanClassLoaderAware及ResourceLoaderAware BootstrapContextAware BeanNameAware,简单的来看几个:

    • BeanFactoryAware:声明BeanFactory
    • BeanClassLoaderAware:是spring类的bean加载器
    • BeanNameAware: 是spring用来申明bean的名字

    直接来看激活Aware的方法

    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            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);
            }
        }
    }
    

    代码简单,就不多说啥了,接着我们来看前置处理器的应用

    前置处理器的应用

    BeanPostProcessor相信大家不陌生,这是spring框架中的一个亮点,其主要的作用是:如果我们想要在 Spring 容器完成 Bean 的实例化,配置和其他的初始化后添加一些自己的逻辑处理,那么请使用该接口,该接口给了用户充足的权限去更改或者扩展 Spring是,我们对 Spring 进行扩展和增强处理一个必不可少的接口,直接看代码:

    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;
    }
    

    上述是前置处理代码,我们再来看后置处理代码:

    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {
    
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
    

    关于前置和后置处理,该方法都是实现接口BeanPostProcessor接口,我们也可以实现该接口来实现对bean的逻辑处理,方法简单就不多说了,最后我们来看激活自定义的init方法

    激活用户自定义的方法

    何为自定义的init方法这样说可能很蒙蔽,我们可能最熟悉的是在配置文件中有时候会使用init-method,其实这里说的就是该方法,直接看代码;

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {
        //首先是检查是否是InitializingBean,如果是需要调用afterPropertiesSet
        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
            }
            //在系统安全管理器的环境下
            if (System.getSecurityManager() != null) {
                try {
                    AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                        //1.属性初始化后的处理
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                //同上
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }
    
        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                //2.激活自定义方法的入口
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
    

    上述代码是激活用户自定义init方法的过程,简单的小结一下:

    • 首先是对bean的判断是否是InitializingBean,是的话需要调用#afterPropertiesSet()来处理,这里考虑到了另外的一种方式是通过实现InitializingBean接口的方法,并非来自我们的init-method配置
    • 判断完之后,接着是对属性的初始化过程,具体实现我们后面来说
    • 最后调用#invokeCustomInitMethod(...)完成真正的激活过程,具体详解后面说.

    到这里我们一个完整的bean从创建到属性填充在到循环依赖的处理最后是完成初始化就说完了,后续的文章中我们来一起学习下spring容器的扩展部分

    相关文章

      网友评论

          本文标题:spring容器之创建bean的终结篇

          本文链接:https://www.haomeiwen.com/subject/arjzlctx.html