clearByTypeCache方法深入解析

private void clearByTypeCache() {
		this.allBeanNamesByType.clear();
		this.singletonBeanNamesByType.clear();
	}

看看clearByTypeCache()方法的代码,做的事情很简单,就是清楚这两个map,那么这两个map到底是啥玩意呢?

	/** Map of singleton and non-singleton bean names, keyed by dependency type.
	 *缓存了依赖项key是依赖项的类型  value是名字
	 * */
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

	/** 仅依赖单例的bean名称的映射,由依赖项类型作为键 */
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

可以看到这两个都是ConcurrentHashMap,这个和逻辑分析没太大关系哈,allBeanNamesByType map,key:bean 的 type, value:bean的名字

singletonBeanNamesByType就是仅仅存单例的,而这两个map里面的对象是怎么put进去的呢,点着查一查

@Override
	public String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
		//这个判断只有第一个有意义!isConfigurationFrozen()
		//判断是否冻结了bd,如果冻结了则返回的false,则不会进if里
		//如果进了if就会调用里面,就表示要去查找
		if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
			return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
		}
		//第一次找依赖bean是走缓存
		//把allBeanNamesByType或者singletonBeanNamesByType赋给了cache
		Map<Class<?>, String[]> cache =
				(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
		String[] resolvedBeanNames = cache.get(type);
		if (resolvedBeanNames != null) {
			return resolvedBeanNames;
		}
		//如果缓存中没有则查找和前面if是一样的
		resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);

		//找到了则put进cache
		if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
			//缓存
			cache.put(type, resolvedBeanNames);
		}
		return resolvedBeanNames;
	}

会看到是在这个方法里面对其进行了操作,将这两个map赋值给cache,再put对象进去。

可以得知这是一个cache,一个缓存,是要做缓存用的,那缓存的是什么呢?看名字哈getBeanNamesForType,根据类型得到beanname,这不是和上面这两个map有关系了,这两个map就是以key:type,value:beanname,这样存的呀。

仔细分析分析这个方法的代码。

if里面可以看到有三个判断,后面两个判断都是通过参数来的,都是默认为false,所以看第一个判断

这个判断其实又跟BeanFactoryPostProcessor的扩展点的API有关系

	/**
	 * 冻结所有bean定义,表示已注册的bean定义将不会被进一步修改或后处理。
	 * <p>This allows the factory to aggressively cache bean definition metadata.
	 */
	void freezeConfiguration();

	/**
	 * Return whether this factory's bean definitions are frozen,
	  i.e. are not supposed to be modified or post-processed any further.
	 * @return {@code true} if the factory's configuration is considered frozen
	 */
	boolean isConfigurationFrozen();



	@Override
	public void freezeConfiguration() {
		this.configurationFrozen = true;
		this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
	}



	@Override
	public boolean isConfigurationFrozen() {
		return this.configurationFrozen;
	}

看看那个接口的方法,和实现类的重写方法。

表示的是冻结,和是否冻结。这个调用了,所以默认是为true,所以!isConfigurationFrozen()肯定是false,不会进入这个if里面。

会走下面,下面就是这两个map对cache的一个赋值,includeNonSingletons是这个方法的参数,看名字得知是包括不是单例的,点查看,发现基本上都是true,所以默认true吧,就把allBeanNamesByType赋值给cache,不包括单例的就是用另外一个map,里面存的都是单例的。

然后会调用这个缓存,通过type看能不能get到 beanname,如果get不到,那么还是得调用和if里面一样的方法doGetBeanNamesForType,这个方法里面就会从

另外的缓存里面查,那这就要经过更多的调用了,所以这里用cache作为缓存,节省时间。

其实getBeanNamesForType,也就是和咋们的getBean有很大关系,spring就是先通过这样的个方法,得到beanname,再调用doGetBean,通过beanname从单例池或者其他地方得到Bean。

而clearByTypeCache方法,就是将这两个key:type,value:BeanName的map,也就是缓存清除。

那么说到缓存,肯定会有个东西要考虑,也就是缓存的更新。

写linux的文章里面也有过那个TLB,页的虚拟地址到物理地址映射的个缓存,可以看到每次页表项映射的物理内存每次发生变化的时候,都会刷新TLB。

而这个缓存是什么时候更新的呢?

这就跟标题呼应了,也就是这个clearByTypeCache清除掉,然后再通过getBeanNamesForType代码里put进cache里的。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值