4, 注解spring-DefaultListableBeanFactory

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图


DefaultListableBeanFactory.jpg

面对这些比较庞大的类图关系, 我们怎么看呢?

1, 我们要清楚最基本的uml中类之前的关系的表示(这个就不多讲了, 百毒一下)

怎么看UML类图

2, 分割看, 因为类图依赖关系比较复杂, 我们需要把他切割出来, 并且有顶层接口往实现类看。

上面我们发现有3个顶层接口: 1, AliasRegistry、2, SingletonBeanRegistry、3, BeanFactory

AliasRegistry

在uml图中, 我们发现AliasRegistry 有一个单独属于其的子类实现SimpleAliasRegistry。

AliasTegistry_src.jpg

我们知道一个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运行, 我们就能发现其调用栈, 我们能够更快的捋顺其调用顺序和时机。

acdI8H.jpg
--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);
}


acshIP.jpg

对于Bean多个别名的时候, 他会将第一个当做Bean的名字, 而将其他的当做别名, 然后保存为 别名 -> beanName的映射, 也就是说多个别名会找到唯一的beanName, 唯一的beanName会找到实体类。

下面让我们康康是如何从别名获取到对象的?

acHD00.jpg
--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的?

dDgHYj.jpg
--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

dDhoJe.jpg

看到这里我们大概知道BeanFactory的作用了

总结

我们通过了DefaultListableBeanFactory的三个顶层接口, 大概了解了其作用:

  1. 存储别名
  2. 存储单利Bean
  3. 获取Bean实例
  4. BeanDefinition的管理

第四条未说, 看上面的第一图, 其中BeanDefinitionRegister继承了AlisRegister, DefaultListableBeanFactory实现了BeanDefinitionRegister。

demo地址