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的流程()
- A-b ,A中需要注入b,那么就需要getBean(B.class)
- 通过上面getBeanNamesForType获取从beanDeinifitionMap到这个bean的名称
- 在通过这个beanName,到singletonObjects获取bean
- 如果没有的话,那么就会根据这个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要提前