DefaultListableBeanFactory
当我们new AnnotationConfigApplicationContext(), 根据源码发现, AnnotationConfigApplicationContext继承了GenericApplicationContext, 初始化会先初始化父类,调用父类的无参构造, 我们发现默认的spring的BeanFactoy的默认实例为DefaultListableBeanFactory。
AnnotationConfigApplicationContext.java
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
GenericApplicationContext.java
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
}
现在让我们看看DefaultListableBeanFactory的uml图
面对这些比较庞大的类图关系, 我们怎么看呢?
1, 我们要清楚最基本的uml中类之前的关系的表示(这个就不多讲了, 百毒一下)
2, 分割看, 因为类图依赖关系比较复杂, 我们需要把他切割出来, 并且有顶层接口往实现类看。
上面我们发现有3个顶层接口: 1, AliasRegistry、2, SingletonBeanRegistry、3, BeanFactory
AliasRegistry
在uml图中, 我们发现AliasRegistry 有一个单独属于其的子类实现SimpleAliasRegistry。
我们知道一个Bean对应多个alias(别名), 那spring是如何处理别名并根据别名获取到对象的?
TestBean06.java
@Component
public class TestBean06 {
@Bean({"aaa", "bbb", "ccc"})
public TestBean06 getBean(){
TestBean06 testBean06 = new TestBean06();
return testBean06;
}
}
SpringTest04.java
public static void main(String[] args) {
String packageName = SpringTest04.class.getPackage().getName();
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(packageName);
Object aaa = annotationConfigApplicationContext.getBean("aaa");
Object bbb = annotationConfigApplicationContext.getBean("bbb");
Object ccc = annotationConfigApplicationContext.getBean("ccc");
Object testBean06 = annotationConfigApplicationContext.getBean("testBean06");
System.out.println(aaa);
System.out.println(bbb);
System.out.println(ccc);
System.out.println(testBean06);
}
-->
top.itkaoti.test04.TestBean06@706a04ae
top.itkaoti.test04.TestBean06@706a04ae
top.itkaoti.test04.TestBean06@706a04ae
top.itkaoti.test04.TestBean06@6eceb130
<--
我们发现aaa,bbb和ccc是同一个对象, 说明getBean()应该只调用一次, TestBean06我们之前看过就是通过构造方法反射获取的, 所以和aaa,bbb不同。
我们跟踪一下源码, 来看下spring是如何设置别名的?
小技巧: 根据类图关系, 我们大概可以猜测注册别名的活,大概率是SimpleAliasRegistry干的, 因此我们直接在SimpleAliasRegistry.registerAlias(...)打上断点, debug运行, 我们就能发现其调用栈, 我们能够更快的捋顺其调用顺序和时机。
--1, AnnotationConfigApplicationContext-->
# 说明已经扫描过BeanDefinition了
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
// 点进去
refresh();
}
--2, -->
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
// 这里面有注册别名的功能
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex) {
}
}
}
# 这边我们就直接看重点代码, 就不一步一步的走了
--3, ConfigurationClassBeanDefinitionReader-->
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
// 获取了方法名
String methodName = metadata.getMethodName();
...
// 判断改方法是否添加了@Bean注解
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
Assert.state(bean != null, "No @Bean annotation attributes");
// 获取所有的@Bean里设置的name值
List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
// 把第一个当做bean的名字, 其他为剩下的为别名
String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
// 注册别名
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
...
}
--4, SimpleAliasRegistry-->
@Override
public void registerAlias(String name, String alias) {
// 关键将别名保存到map中
this.aliasMap.put(alias, name);
}
对于Bean多个别名的时候, 他会将第一个当做Bean的名字, 而将其他的当做别名, 然后保存为 别名 -> beanName的映射, 也就是说多个别名会找到唯一的beanName, 唯一的beanName会找到实体类。
下面让我们康康是如何从别名获取到对象的?
--1, SpringTest04.java-->
Object ccc = annotationConfigApplicationContext.getBean("ccc");
--2, AbstractApplicationContext-->
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
--3, AbstractBeanFactory-->
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
--4, AbstractBeanFactory-->
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 由别名ccc找到aaa
String beanName = transformedBeanName(name);
Object bean;
// 再由aaa找到实体类
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}
SingletonBeanRegistry
见名知意, 应该和上面的AliasRegistry功能类似, AliasRegistry存储别名, 那么这个应该就是存储单例Bean对象的。
那么我们就应该知道,接口只是规定器功能, 具体功能实现应该就是在其实现类中, 那么其子类应该也有一个Map来存储beanName和实体类。
现在让我看看DefaultListableBeanFactory是如何注册存储bean的?
--1, SpringTest04-->
public class SpringTest04 {
public static void main(String[] args) {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
TestBean41 testBean41 = new TestBean41();
factory.registerSingleton("testBean41", testBean41);
Object testBean411 = factory.getSingleton("testBean41");
System.out.println(testBean41 == testBean411);
}
}
--2, DefaultListableBeanFactory-->
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
// 点进去
super.registerSingleton(beanName, singletonObject);
updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));
clearByTypeCache();
}
--3, DefaultSingletonBeanRegistry-->
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
// 一些校验
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
// 已经注册过了
throw new IllegalStateException(..);
}
// 点进去
addSingleton(beanName, singletonObject);
}
}
--4, DefaultSingletonBeanRegistry-->
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
原来在DefaultSingletonBeanRegistry中的singletonObjects里存储了单利Bean的实例, DefaultListableBeanFactory也继承DefaultSingletonBeanRegistry。
BeanFactory
看到这里我们大概知道BeanFactory的作用了
总结
我们通过了DefaultListableBeanFactory的三个顶层接口, 大概了解了其作用:
- 存储别名
- 存储单利Bean
- 获取Bean实例
- BeanDefinition的管理
第四条未说, 看上面的第一图, 其中BeanDefinitionRegister继承了AlisRegister, DefaultListableBeanFactory实现了BeanDefinitionRegister。