【Spring-IOC】SpringIOC容器-bean的解析封装为BeanDefinition

我们在用context获取bean的时候,其实底层都是操作的DefaultListableBeanFactory这个类。这个类中主要分为两块:

  1. 注册bean:解析class,封装为beanDefinition对象;
  2. 从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(<
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值