我们在用context获取bean的时候,其实底层都是操作的DefaultListableBeanFactory这个类。这个类中主要分为两块:
- 注册bean:解析class,封装为beanDefinition对象;
- 从beanDefinition中实例化对象。
先看下是如何保存数据的。
beanDefinition对象
DefaultListableBeanFactory中的属性:
// key:bean的名称
// value:BeanDefinition对象
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
//通过类型保存key:类型,value:bean的名称
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
// 这里只保存了单例的
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
// 所有bean的名称
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
// 手动添加的bean的名称
// 为什么有手动添加的呢?因为我们可以操作context,添加自己的BeanDefinition,这就是手动添加的,会加入到这个set中。
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
实例对象
从DefaultListableBeanFactory一直找父类,会找到DefaultSingletonBeanRegistry
//bean名称 bean实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//保存的是ObjectFactory的类
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//早期暴露的bean,用于解决循环依赖
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 实例的名称。
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
知道了在哪里保存数据,那么就开始看从哪里开始解析类,并封装为beandefinitions类。由于spring支持配置文件和注解。所以分别看下是如何注册bean的。
ClassPathXmlApplicationContext 解析配置文件注册bean
我们在使用的时候通常都是这样创建的:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
传入spring的配置文件,通过解析里面的配置,注册到容器中。
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 设置配置文件的路径
setConfigLocations(configLocations);
if (refresh) {
// 调用刷新方法。
refresh();
}
}
刷新方法在org.springframework.context.support.AbstractApplicationContext#refresh()
,这里面有众多的方法。xml的解析在obtainFreshBeanFactory
方法中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新工厂,并将工厂返回
refreshBeanFactory();
return getBeanFactory();
}
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
protected final void refreshBeanFactory() throws BeansException {
// 如果已经有了,就销毁,重新创建。
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 实例化工厂,就是创建DefaultListableBeanFactory对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 将配置文件中的配置,注册到beanFactory中。
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
XmlBeanDefinitionReader实例化的时候已经将beanFactory放进入了,现在传入配置文件的路径。
继续深入,找到方法:
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
通过命名空间,解析标签。就行,,在不同的命名空间下
先看本命名空间下的:
private void parseDefaultElement(<