Spring源码学习(四)BeanFactoryPostProcessor接口(二)

本文深入探讨Spring框架中Bean的缓存机制,包括DefaultListableBeanFactory中的clearMetadataCache和clearByTypeCache方法,以及如何通过缓存提高依赖注入效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BeanFactoryPostProcessor接口

clearMetadataCache()

clearMetadataCache需要了解冻结 freezeConfiguration()这个方法

clearMetadataCache的实现是 DefaultListableBeanFactory 中

// DefaultListableBeanFactory.java
@Override
public void clearMetadataCache() {
    // 会根据冻结来判断merge缓存
    //  protected boolean isBeanEligibleForMetadataCaching(String beanName) {
    //    return (configurationFrozen || super.isBeanEligibleForMetadataCaching(beanName));
    //}
	super.clearMetadataCache();
	// 清楚merged缓存
	mergedBeanDefinitionHolders.clear();

	// 清楚缓存的依赖性   为什么要清楚呢?在什么时候做的缓存
	clearByTypeCache();
}
clearByTypeCache()
    // DefaultListableBeanFactory.java
	private void clearByTypeCache() {
    	// 缓存的是依赖项的bean,例如A 中的属性 b ,那么b就需要被缓存 kv的格式是 class-     		beanNames(为什么是数组,一个bean可以起多个名字,正常情况不用考虑)
        allBeanNamesByType.clear();
        
        // 这边是缓存单例的,allBeanNamesByType 包含了  singletonBeanNamesByType
        singletonBeanNamesByType.clear();
    }
allBeanNamesByType

allBeanNamesByType和singletonBeanNamesByType什么是放进去的呢?为什么要放进去?

allBeanNamesByType主要作用是,注入的时候作为,缓存依赖项。用于根据通过bean的类型,获取bean的名字

    // DefaultListableBeanFactory.java 
    /**
     * 	通过bean的类型,获取bean的名字
     * 	在什么是调用呢?
     *	因为在注入的时候,是根据类型来注入的,
     *	那么就先获得类型,获得类型后然后需要获取到beanName,才能到beanDefinitionMap(其实是到单例池(一级缓存)中去找这个实例)
     *	,拿到beanDefinition,来创建bean。
     */
    @Override
    public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        /**
         * isConfigurationFrozen 有没有被冻结
         * type正常都是false
         * allowEagerInit是否是懒加载,就是A中需要b,注入的时候是否需要直接实例化b?spring默认是true的
         *
         * 当A注入b的时候
         * 什么时候会被冻结呢?
         * 在开始实例化(refresh() --> finishBeanFactoryInitialization -->preInstantiateSingletons)之前这个class已经被冻结了,
         * 1.冻结则不会进if,那么就会走缓存;
         * 2.没有冻结了则会近if会去查找(性能损耗)
         */
        if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
            return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
        }
        Map<Class<?>, String[]> cache = (includeNonSingletons ? allBeanNamesByType : singletonBeanNamesByType);
        // 第一次A-b注入肯定是找不到的,后面再次C-b注入会找到
        String[] resolvedBeanNames = cache.get(type);
        if (resolvedBeanNames != null) {
            return resolvedBeanNames;
        }
        // 找不到则和没有冻结一样进if去找,然后返回加入缓存
        resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
        if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
            cache.put(type, resolvedBeanNames);
        }
        return resolvedBeanNames;
    }
singletonObjects

单例池,spring中所有实例好的单例bean都会放在里面

Demo

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

//@Component
//@Scope("prototype")
public class TestSingleonBean {
}

class DemoTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
        ac.register(TestSingleonBean.class);
        // 和ac.register(TestSingleonBean.class);本质是一样的
        // ac.registerBeanDefinition("testSingleonBean",new RootBeanDefinition());
        ac.refresh();
        // 默认是单例的,打断点可以看到  ac-beanFactory-singletonObjects 存在testSingleonBean
        // 但是若class TestSingleonBean 加上@Component、@Scope("prototype") singletonObjects 缓存中了,但是beanDefinition缓存中是有的
        TestSingleonBean bean = ac.getBean(TestSingleonBean.class);
        System.out.println(bean);
    }
}

spring中getBean的流程()

  1. A-b ,A中需要注入b,那么就需要getBean(B.class)
  2. 通过上面getBeanNamesForType获取从beanDeinifitionMap到这个bean的名称
  3. 在通过这个beanName,到singletonObjects获取bean
  4. 如果没有的话,那么就会根据这个beanDeinifition来创建好bean,然后放入到singletonObjects,再获取这个bean。
registerBeanDefinition()

有缓存肯定会涉及到一致性问题:比如allBeanNamesByType这个缓存和beanDeinifitionMap怎么保持同步?

ac.register(TestSingleonBean.class);

若存在同名的手工bean会清除,然后更新BeanDefinitionMap(更新)

手工注册bean

private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

spring中bean的来源,一个是spring自己的,还有就是程序员提供的。

spring中bean的生成方式,一种是通过beanDefinitionMap的遍历来实例化,还有一个中register bean object,而manualSingletonNames中的bean都是直接注册进来的。

手工bean的生成

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
    // 手工bean的注入,没有beanDefinition的生成,会放入到Set<String> manualSingletonNames中
    ac.getBeanFactory().registerSingleton("testSingleonBean",new TestSingleonBean());

为什么需要有两种的生成方式呢?

直接实例化不具有完整的生命周期。

spring容器初始化完成后会finishRefresh()清除缓存 type-name缓存,自己注册bean完成后也清楚缓存

    @Override
    public void registerBeanDefinition(String beanName,
        BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

        // 查看beanName是否已经被注册
        BeanDefinition existingDefinition = beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            // spring默认支持覆盖beanDefinition,但是会输出日志
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
                // 优先级
            } else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName
                        + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with ["
                        + beanDefinition + "]");
                }
                //
            } else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName
                        + "' with a different definition: replacing [" + existingDefinition + "] with ["
                        + beanDefinition + "]");
                }
            } else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName
                        + "' with an equivalent definition: replacing [" + existingDefinition + "] with ["
                        + beanDefinition + "]");
                }
            }
            beanDefinitionMap.put(beanName, beanDefinition);
        } else {
            // bean 是否已经开始创建,是整个容器是否已经开始创建
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                // 防止线程安全问题,集合防止在运行中被修改
                synchronized (beanDefinitionMap) {
                    beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            } else {
                // 表示没有在创建,那么直接加入就可以了
                // Still in startup registration phase
                //beanDefinitionMap 和 beanDefinitionNames 更新
                beanDefinitionMap.put(beanName, beanDefinition);
                beanDefinitionNames.add(beanName);

                // 删除手工单例的名字
                // 如果手工注册的bean名字 和 某个已经存在的bean名字相同,则删除手工的
                removeManualSingletonName(beanName);
            }
            frozenBeanDefinitionNames = null;
        }

        // 判断注册的beanDefinition是否存在
        if (existingDefinition != null || containsSingleton(beanName)) {
            // 已经存在的bean的则需要更新
            // 1.清除type-name 缓存
            // 2.替换单例池
            resetBeanDefinition(beanName);
        } else if (isConfigurationFrozen()) {
            // 不存在的bean,在添加完BeanDefinition,需要判断是否被冻结了
            // 被冻结可能正在实例化了,那么就可能会有缓存,那么就需要清除type-name缓存,因为现在已经更新了
            clearByTypeCache();
        }
    }
freezeConfiguration();

bean原型的话,则不会创建,调用的时候才会被创建

如果在对beanFactory设置冻结属性,那么本次注入对beanDefinition的修改均无效。后续会有效

因为如果冻结的,那么就不会添加到merge缓存中,其实spring实例化不是通过beanDefinitionMap来直接获取的,

而是通过mergedDefinitionMap来获取的。

bfbd修改为冻结,只会对doGetBean–>markBeanAsCreated方法之前的代码生效,因为markBeanAsCreated这个方法会重新mergebd

mergedDefinitionMap

**mergedBeanDefinitionMap是什么?**为什么需要mergedBeanDefinitionMap?

因为bd存在父子关系

rootBeanDefinition childBeanDefinition

child可以继承root,spring后期又提供了GenericBeanDefinition来优化,可以直接setParentName();

1.注册a,b两个beanDefinition

2.设置b-db的父类为a-bd

3.将a-bd、b-db放入bdmap

4.refsh(),时候合入到mergebdmap,然后在mergebdmap获取这个beanName,实例化。

为什么需要mergedBeanDefinitionMap?

因为bd是可以修改的,那么实例化过程中,有可能会被改动,而且bean会被获取多次,那么就会反复去merge,然后拿merge的bd。

**在哪边需要合并呢?**在实例化spring内置的beanFactoryPostProcessor获取类型缓存的时候,doGetBeanNamesForType

beanFactoryPostProcessorbean的实例化,比普通的bean要提前

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值