暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring架构及源码分析(三)Beandefination

云程序员的云技术 2021-11-26
365

         在上篇文章中,我们讨论了 refresh 的前四个方法,主要是对 ApplicationContext 上下文启动做一些准备工作。接下来对 invokeBeanFactoryPostProcessors 方法进行讨论,但该方法涉及 Spring 中一个非常重要的概念: BeanDefinition,所以,这里先对 BeanDefinition 进行讨论,这样也有利于完善 Spring 的知识体系。

首先看一下Spring一个大概的流程处理过程。

读取XML-> 解析XML封装成DOC对象 ->  DOC对象转换成Spring beanDefinition对象 ->   获取beanDefinition对象开始创建bean

        Spring容器启动的过程中,会将Bean定义信息解析成Spring内部的BeanDefinition结构。

Bean信息定义4种方式

        1.API方式

        2.XML文件方式

        3.注解方式

            类上标注@Compontent注解来定义一个bean

            配置类中使用@Bean注解来定义bean

        4.properties文件的方式

        不管是是通过xml配置文件的标签,还是通过注解配置的@Bean,还是@Compontent标注的类,还是扫描得到的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。

        BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean,一个 BeanDefinition 描述了一个 Bean 实例,实例包含属性值、构造方法参数值以及更多实现信息。下面以XML文件配置方式从源码上跟一下BeanDefinition的注册过程。

1. 首先在ClassPathXmlApplicationContext设置了xml文件的位置,然后调用AbstractApplicationContext的refresh()方法。

public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
//创建解析器,解析configLocations
setConfigLocations(configLocations);
if (refresh) {
// 核心方法
refresh();
}
}

2.AbstractApplicationContext里obtainFreshBeanFactory()方法解析xml标签封装成BeanDefinition对象。


// AbstractApplicationContext.java
/*
* 该方法是spring容器初始化的核心方法。是spring容器初始化的核心流程,是一个典型的父类模板设计模式的运用
* 根据不同的上下文对象,会调到不同的上下文对象子类方法中
*
* 核心上下文子类有:
* ClassPathXmlApplicationContext
* FileSystemXmlApplicationContext
* AnnotationConfigApplicationContext
* EmbeddedWebApplicationContext(springboot) 里面会用到钩子方法启动内嵌tomcat
* */
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {

//为容器初始化做准备
prepareRefresh();

/*
非常重要
1、创建BeanFactory对象
* 2、xml解析
* 传统标签解析:bean、import等
* 自定义标签解析 如:<context:component-scan base-package="com.xiangxue.jack"/>
* 自定义标签解析流程:
* a、根据当前解析标签的头信息找到对应的namespaceUri
* b、加载spring所以jar中的spring.handlers文件。并建立映射关系
* c、根据namespaceUri从映射关系中找到对应的实现了NamespaceHandler接口的类
* d、调用类的init方法,init方法是注册了各种自定义标签的解析类
* e、根据namespaceUri找到对应的解析类,然后调用paser方法完成标签解析
*
* 3、把解析出来的xml标签封装成BeanDefinition对象
* */
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

......
}
}

3.AbstractApplicationContext里obtainFreshBeanFactory()调用refreshBeanFactory方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
......
}

4.refreshBeanFactory方法调用loadBeanDefinitions方法

@Override
protected final void refreshBeanFactory() throws BeansException {
......
try {


loadBeanDefinitions(beanFactory);
}
......
}

5.在loadBeanDefinitions方法中创建XmlBeanDefinitionReader 对象用于解析xml文件

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);


// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));


// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

6.继续追踪loadBeanDefinitions方法,发现最后XmlBeanDefinitionReader 类中调用doLoadBeanDefinitions方法


public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
......
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
......
}
......
}

7.doLoadBeanDefinitions方法中把xml文件解析成document对象,然后注册BeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
......
}

 8.继续调用registerBeanDefinitions方法,最终在DefaultBeanDefinitionDocumentReader类中调用doRegisterBeanDefinitions方法


@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}

 9.doRegisterBeanDefinitions中调用parseBeanDefinitions方法

protected void doRegisterBeanDefinitions(Element root) {
......


preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);


this.delegate = parent;
}

10.parseBeanDefinitions方法中调用parseDefaultElement方法

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);
}
}
}
}


}

11.parseDefaultElement方法中调用processBeanDefinition方法 

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

12.processBeanDefinition方法中调用registerBeanDefinition


protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
......
}

13.继续调用registerBeanDefinition方法,最终在DefaultLisableBeanfactory中把bean低昂易信息解析成BeanDefiantion对象并put到beanDefinitionMap中,把beanDefinition的名字add到beanDefinitionNames列表中

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {



......
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}


......
}

14.执行完 registerBeanDefinition 方法后,Bean 的名称就被放入了beanDefinitionNames中,Bean 对应的 BeanDefinition被放入了beanDefinitionMap中,refresh方法中的后续方法会从这两个容器中获取beandefination信息来实例化bean对象。

文章转载自云程序员的云技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论