美文网首页
spring-BeanFactory学习(一)

spring-BeanFactory学习(一)

作者: 非典型_程序员 | 来源:发表于2019-03-31 19:26 被阅读0次

上周主要了解了spring boot项目启动过程中,beanFactory的继承体系,以及beanFactory是怎么创建的。今天继续来看下beanFactory这个容器的详细信息,因为beanFactory属性和方法比较多,今天主要看下它比较重要的几个属性和方法。

一、属性

beanFactory负责管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的声明周期,再加上DefaultListableBeanFactory的父类也比较多,也导致了beanFactory属性非常的多。下面是我认为比较重要的一些属性,这些属性可能是定义在DefaultListableBeanFactory类中,也可能定义在其父类中,但是为了方便我就全部写到一起了,下面是代码:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    // 继承子父类的属性
    // 创建bean实例的策略,使用的是cglib
    private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
    // 是否自动尝试解析bean之间的循环引用
    private boolean allowCircularReferences;
    // 在依赖性检查和自动装配时忽略的依赖关系类型,存储的为Class对象
    private final Set<Class<?>> ignoredDependencyTypes;
    // 在依赖性检查和自动装配时忽略的依赖关系类型,存储的为Class对象。默认值忽略BeanFactory
    private final Set<Class<?>> ignoredDependencyInterfaces;
    // 当前正在创建的bean的名称,用于从用户指定的Supplier回调触发的getBean等调用的隐式依赖注册。
    private final NamedThreadLocal<String> currentlyCreatedBean;
    // 是否缓存bean的元数据,或者每次访问时重新获取
    private boolean cacheBeanMetadata = true;
    // 要在createBean中应用的BeanPostProcessors
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList();
    // 从bean名称映射到合并的RootBeanDefinition
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap(256);
    // 已经创建至少一次的bean的名称
    private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap(256));
    // 当前正在创建的bean的名称
    private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal("Prototype beans currently in creation");    

    // 本身的属性值//
    // 是否允许使用相同bean名称重新注册不同的bean定义,即注册的两个相同的名字的bean,且用后面的bean覆盖前面的
    private boolean allowBeanDefinitionOverriding = true;
    // 是否允许预加载
    private boolean allowEagerClassLoading = true;
    // 检查bean定义是否为一个autowire注入的解析器
    private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
    // 根据依赖类型映射到相应的自动注入的值map集合
    private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap(16);
    // 键值是bean名称,映射值为bean定义对象的map集合
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
    // 以依赖类型的类对象为键,所有bean(单例非单例)的名称为值得map集合
    private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap(64);
    // 以依赖类型的类对象为键,所有单例bean的名称为值的map集合
    private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap(64);
    // bean定义的名称list,按照注册顺序
    private volatile List<String> beanDefinitionNames = new ArrayList(256);
   
    // 省略
    ....
}

看到这里我就记得上次中遇到的一个问题,就是同名bean的创建,当时日志显示的当前bean的类型不是期望的类型,因为allowBeanDefinitionOverriding的属性值默认为true。当然这个属性是可以修改的,有兴趣可以网上找一下相关方法。有些属性又会涉及到很多不太熟悉的类,比如AutowireCandidateResolver、BeanDefinition、RootBeanDefinition等等,AutowireCandidateResolver是检查bean是否通过Autowire注入的解析器。BeanDefinition描述了一个bean实例,它保存相关的属性值,构造函数参数值以及具体实现提供的更多信息。RootBeanDefinition表示合并的bean定义,它在运行时支持BeanFactory中的特定bean,它本质上是运行时的“统一”bean定义视图。反正遇到不清楚的就去看下源码的注解,有时不一定非要特别清楚,了解它的作用就行。接下来我们看下相关的一些方法吧,同样的,这些方法可能是DefaultListableBeanFactory类,也可能是其父类的。

二、相关方法

方法也非常多,一样选择几个来看。beanFactory负责bean的加载、实例化以及相互之间的关系,我们对应一个一个。

1、创建bean

创建bean的方法来自于AbstractAutowireCapableBeanFactory,下面我们看看源码,简单的分析一下大概的过程。

public <T> T createBean(Class<T> beanClass) throws BeansException {
    RootBeanDefinition bd = new RootBeanDefinition(beanClass);
    bd.setScope(SCOPE_PROTOTYPE);
    bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
    return (T) createBean(beanClass.getName(), bd, null);
}

首先以类对象为参数创建出RootBeanDefinition实例,然后设置其为原型模式,即prototype,这样的目的就是为了避免它作为一个依赖bean存在,因为每个RootBeanDefinition创建都需要一个对应的bean的类对象。然后调用下面的方法

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }

这个方法里面先执行resolveBeanClass(mbd, beanName)方法,即根据RootBeanDefinition实例和bean名称为参数,去解析对应的类对象,返回结果为bean名称的类对象。这个过程中会将已解析的Class存储在bean定义中以供进一步使用。然后执行prepareMethodOverrides方法,该方法主要为了验证并准备为此bean定义的方法覆盖,检查其是否存在具有指定名称的方法。然后是resolveBeforeInstantiation方法,即在实例化之前解析,这个方法为BeanPostProcessors提供返回代理对象而不是目标bean实例的机会,也就是说如果在实例化之间检验是否有这个bean的一个代理对象,有的话直接返回该代理对象,否则继续执行下面doCreateBean方法,我们看下doCreateBean源码

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {

        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }

        Object exposedObject = bean;
        try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton(beanName, false);
            if (earlySingletonReference != null) {
                if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                    String[] dependentBeans = getDependentBeans(beanName);
                    Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                    for (String dependentBean : dependentBeans) {
                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                            actualDependentBeans.add(dependentBean);
                        }
                    }
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }

        try {
            registerDisposableBeanIfNecessary(beanName, bean, mbd);
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
        }

        return exposedObject;
    }

1、这个方法先判断RootBeanDefinition是否为单例,如果为单例则从factoryBeanInstanceCache中移除该bean名称,否则执行2。
2、执行createBeanInstance方法创建bean实例,这个方法会使用适当的实例化策略为指定的bean创建新实例:比如工厂方法,构造函数自动装配或简单实例化,返回结果是一个bean的包装类对象。getWrappedInstance和getWrappedClass方法反别返回相应的bean对象和bean的类对象,并将该类对象赋值给resolvedTargetType。
3、接下来的同步代码块主要是为了允许post-processors(后处理器)修改合并的bean定义,即将MergedBeanDefinitionPostProcessors应用于指定的bean定义,并调用其postProcessMergedBeanDefinition方法。关于这点我也还不是太理解具体的作用。
4、判断是否支持earlySingletonExposure,即热缓存单例,以保证即使在BeanFactoryAware等生命周期接口触发时也能够解析循环引用。如果是则将创建新的单例工厂以构建指定的单例bean。
5、初始化bean实例,先执行populateBean方法,即使用bean定义中的属性值填充给定bean的包装类对象中的bean实例。然后执行initializeBean方法,初始化给定的bean实例,应用工厂回调以及init方法和bean后处理器。
6、判断earlySingletonExposure属性值,如果为true,则获取早期的单例bean引用,如果不为空进行后续判断判断初始化后的exposedObject和第2步中的bean是否同一个bean,是将将早期单列bean引用赋值给exposedObject,否则继续进行其他判断。
7、执行registerDisposableBeanIfNecessary方法,将bean注册为一次性bean。最后返回相应bean实例。
当然我说是比较简单的,其实中间过程非常的复杂,因为涉及的方法很多,自己没办法每一个都贴一段代码,所以只能将就看吧。
2、初始化bean
初始化给定的bean实例,应用工厂回调以及init方法和bean后处理器。这个在上面的createBean方法中有调用过,我们看下具体的代码

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

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

1、判断系统的securityManager是否为null,不为null执行AccessController.doPrivileged方法;否则执行2。
2、执行invokeAwareMethods方法,该方法两个参数,分别为bean名称beanName和实例bean。判断给定的bean是否为BeanNameAware实例,是则将bean实例名称设置为beanName;判断给定的bean是否为BeanClassLoaderAware实例,然后获取ClassLoader,不为空是则将ClassLoader引用赋值给bean的beanClassLoader变量;最后判断bean实例是否为BeanFactoryAware,是则调用setBeanFactory方法,将AbstractAutowireCapableBeanFactory实例赋值给bean的beanFactory变量。
3、将bean实例赋值给变量wrappedBean,然后判断RootBeanDefinition即mbd是否为null或者mbd为非合成,执行applyBeanPostProcessorsBeforeInitialization方法,该方法会获取到BeanPostProcessor实例,并执行各自的postProcessBeforeInitialization实现,其返回的bean实例可能是是原始实例的包装器对象。
4、执行invokeInitMethods方法,这个方法会将bean所有属性值都被设置,并了解它属于的bean工厂。这个需要检查该bean是否实现了InitializingBean或定义了一个自定义init方法,并调用必要的回调方法。看下面的代码:

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        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((PrivilegedExceptionAction<Object>) () -> {
                        ((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)) {
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

先判断bean是否实现了InitializingBean,如果是,且满足其他判断条件,则执行afterPropertiesSet方法。如果mbd不为null,且bean实例的类对象不为NullBean,则从RootBeanDefinition实例获取initMethodName名称,如果满足判断条件,则执行invokeCustomInitMethod方法,该方法通过反射执行自定义的init方法。
5、执行mbd为null或者mbd.isSynthetic()为false的判断条件,满足条件执行applyBeanPostProcessorsAfterInitialization,即完成初始化后应用BeanPostProcessors方法,该方法和3中的applyBeanPostProcessorsBeforeInitialization方法比较相像,都是执行每个PostProcessor各自的postProcessAfterInitialization方法。最后返回wrappedBean,这个是一个原始bean的包装器对象。


其实初始化bean的方法应该算是创建bean的一个部分,我为了区分就单独拿出来了,今天主要就是了解beanFactory的成员变量以及两个方法,但是这两个方法比我想象的还是要复杂一点,代码还是蛮多的,关于其他的一些方法我们下次继续再看。
最后想说一下周五的一个面试情况,自己虽然投了十几份简历也就那么2、3家面试邀请,但是因为在异地,自己拒了一家。星期五我觉得很有必要去面一下,请假去了上海。周五面的是中通快递,地点很偏僻,面试体验也并不太好,当然自己也没有怎么准备(有点托大,后悔)。面试问题主要是Java基础,多线程我说没怎么用过面试官就没问了,其实这部分自己看得东西也蛮多的;然后spring cloud和dubbo对比,这个我没回答好,缺少实际的使用经验。mybatis的一点基础OGNL表达式和EL表达式的区别,我只记得OGNL能更好的防止SQL注入;redis持久化的两种方式,自认为答的还行,毕竟前段时间刚学了;然后就是Java基础,问的也不多,都是比较常规的,自己觉得回答都还OK。另外数据库索引方面的知识,面试官问索引最优实现以及给了一个场景自己判断需不需要加索引,怎么加索引,虽然自己学了,但是感觉回答的不是很好。面试时间挺短的,自己还等了HR半个小时,后来HR说初始先这样吧,我觉得应该是没戏了,毕竟HR都没面。感觉自己还是需要多出去面试一下,刷下经验。

相关文章

  • spring-BeanFactory学习(一)

    上周主要了解了spring boot项目启动过程中,beanFactory的继承体系,以及beanFactory是...

  • spring-BeanFactory学习(二)

    上周进入了新的项目组,主要是对原有微服务进行优化,然后就遇到了如何将日志分类处理的问题,即将服务之间调用和第三方调...

  • Spring-BeanFactory和FactoryBean的区

    1.BeanFactory和FactoryBean的区别 BeanFactory是一个接口,提供了IOC容器最基本...

  • 学习“学习学习再学习” 一

    上周在复习的时候提到了你想不想要一个人生的“作弊器”?答案是肯定的,而且深入研究之后得知学习的三个境界见“通向财富...

  • 学习“学习之道”(一)

    我们都知道,学习,是一辈子的事。实际上我们人生的前半生都基本是在学习中度过的。来问问大家,读了十年书的,举个手,十...

  • 学习一

    很多方法都是只有用了才会记得住,就像循环函数,多用,就会知道for(){}这样的结构,函数function()...

  • 学习一

    学习! 我写的,所分享的东西都是我看到,听到,以及胡思乱想想到的东西;我只是把触动我的内容转述出来。我所说的一切都...

  • 学习(一)

    任何一个企业要想在剧烈变动的市场中生存和发展,必须有能力及时察觉组织内外环境的变化,并积极做出调整,学习新的技能,...

  • 学习(一)

    早上我和同事S姐来到学习的超市,我们先熟悉了环境。 紧接着,我们和促销人员聊天,促销人员给我们讲了一些基本的知识。...

  • 学习(一)

    细雨绵绵的上海,走在路上,带着凉风习习,寒气逼人。 昨天有听了深度工作,就是专心,今天就试了一下,手机放在一边,调...

网友评论

      本文标题:spring-BeanFactory学习(一)

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