文章目录
前言
在分析Spring IOC中bean的创建执行流程的时候,遇到了这么一个对象BeanDefinition,其实呢这个也挺重要的,bean工厂创建对象就是根据这个来的,这里面记录了装配到容器中所有的bean对象信息,由于篇幅过长就单独提出来写了一篇文章来介绍。
一、BeanDefinition
继续顺着前面的思路走,前面说到在刷新获取BeanFactory的时候做了这么一件事:加载BeanDefinition
loadBeanDefinitions(beanFactory);
我们找到BeanDefinition,由于它是个接口我们看它默认的实现子类AbstractBeanDefinition。咱看一下这个类里面的一些属性,其实就可以看出来,这个装载了很多我们初始化bean配置的信息,例如单例、懒加载等。
...
private volatile Object beanClass;
private String scope = SCOPE_DEFAULT; //单例,默认为单例
private boolean abstractFlag = false;
private Boolean lazyInit; //是否懒加载
private int autowireMode = AUTOWIRE_NO; //自动装配
private int dependencyCheck = DEPENDENCY_CHECK_NONE; //默认不检查依赖
private String[] dependsOn; //依赖的bean列表
private boolean autowireCandidate = true;
private boolean primary = false;
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();
private Supplier<?> instanceSupplier;
private boolean nonPublicAccessAllowed = true;
private boolean lenientConstructorResolution = true;
private String factoryBeanName; //创建bean的bean工厂名称
private String factoryMethodName; //创建bean的bean工厂方法
private ConstructorArgumentValues constructorArgumentValues; //有参构造的参数
private MutablePropertyValues propertyValues; //bean的属性及对应名称
private MethodOverrides methodOverrides = new MethodOverrides(); //被覆盖的方法
private String initMethodName; //初始化和销毁方法
private String destroyMethodName;
private boolean enforceInitMethod = true; //是否需要执行初始化和销毁方法
private boolean enforceDestroyMethod = true;
private boolean synthetic = false;
private int role = BeanDefinition.ROLE_APPLICATION;
private String description; //一些描述信息等
private Resource resource; //定义bean的资源
...
看了一下其实这个类没有什么复杂的内容,只是对我们配置的beans.xml进行了解析,然后把相关配置写到了属性中,可以在DefaultListableBeanFactory注册BeanDefinition的方法(registerBeanDefinition)中打个断点看一下。
这个类简单的理解可以当做Bean对象的Entity,我们找一些用到这个类的类,方法其实很简单,用这个类作为开头全局搜一下相关的类分析一下可以找到许多,找几个看一下。
二、BeanDefinitionBuilder
看名称就知道这是BeanDefinition的构建器,具体干啥的呢看一下内部的方法。可以看到其内部的许多方法都与上面的BeanDefinition中的属性相配合的,可以用其手动的构建一个BeanDefinition对象。
来手动试一下:
public static void main(String[] args) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class) ;
beanDefinitionBuilder
.addPropertyValue("name","张三")
.addPropertyValue("age",18)
.setScope("singleton");
BeanDefinition beanDefinition= beanDefinitionBuilder.getBeanDefinition() ;
System.out.println(beanDefinition);//这一行是用来打断点的
}
可以看到可以使用其手动的构建一个BeanDefinition对象
三、BeanDefinitionHolder
BeanDefinition的持有者,其内部有两个属性是beanName也就是XML中配置的BeanId,还有一个是BeanDefinition,方法上没有什么特殊的方法。
四、BeanDefinitionParserDelegate
其实本来想看BeanDefinitionDocumentReader类的,但是其内部涉及到了这个类就先看一下它了,名称直译意思是BeanDefinition转换的委托类,点进去后看到了啥,一堆和Bean的XML配置相关的信息,也就是说它是Bean对象由XML转换为BeanDefinition的委托类。
再里面巴拉巴拉相关的方法,看了其中的方法名就知道核心方法是把XML转换为BeanDefinition对象的方法
//大家应该都知道Element是XML解析完的对象,BeanName是XML中配置的beanID
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
...
try {
//新创建一个BeanDefinition
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//下面是解析相关的内容放到BeanDefinition对应的属性中,具体干啥就不细看了
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
...
}
还有一个重写的方法最终解析为BeanDefinitionHolder,BeanDefinition的持有者对象。
五、BeanDefinitionDocumentReader
同样看名称就明白这是从Document文档例如XML中读取配置BeanDefinition的,直接看一下其核心方法,由于它是个接口,我们看它默认的实现子类DefaultBeanDefinitionDocumentReader中的方法,看其参数是Element类型的,这个大家应该熟悉是XML的解析类型,也就是说到了这里XML已经被解析成了Element对象了,还有一个参数是BeanDefinitionParserDelegate类型的,来解析Element变成BeanDefinition的
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);
}
}
}
}
...
}
//根据断点最终走到了这个方法,最后解析为了持有者对象
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
...
// 发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanComponentDefinition
本来搜不到它的,但是打断点分析的过程用到了它,看一下相关的源代码信息,一个BeanDefinition的数组和一个BeanReference的数组,怎么说呢,这个类继承了BeanDefinitionHolder,但是其内部不是单个的了,而是放了多个相关的BeanDefinition信息。
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
这一行其实是监听器,有没有发现一个问题,当走到这里方法的返回参数为void空的,但是Bean对象的相关配置从XML中解析出来了,发现这里是空的,后面没有了,往回找,肯定是哪个方法漏掉了细节,最终找到了
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
这里最终指向了BeanDefinitionRegistry类,BeanDefinitionRegistry管理类,来看一下。
六、BeanDefinitionRegistry
其实只简单的看了一下BeanDefinition这个类的一些属性可以判断这就是记录bean的一些配置信息,工厂用来实例化bean的时候就根据这些配置信息来获取。咱看一下使用BeanDefinition类的注册类BeanDefinitionRegistry,这是个接口,看其提供的方法都是一些BeanDefinition的管理方法。
public interface BeanDefinitionRegistry extends AliasRegistry {
//注册
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
//移除
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
//获取
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
boolean containsBeanDefinition(String beanName);
String[] getBeanDefinitionNames();
int getBeanDefinitionCount();
boolean isBeanNameInUse(String beanName);
}
具体的其实可以看其子类DefaultListableBeanFactory,里面有这么一个属性,这就是传说中的bean容器,以配置文件中的id为key存放了N多Bean的模板,其实看上面的注册移除管理就比较简单了,可以理解为Map的操作。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
到此,XML解析(当然这只是后面,前面XML解析为Document到Element就不写了,有空再说)为BeanDefinition后面放到容器里的顺序捋清了。
总结
按照上面的分析最终梳理出来这么个逻辑:
- 前面操作把Beans.xml解析成了Document Element对象,这些省略了。
- 调用BeanDefinitionDocumentReader中的parseBeanDefinitions()方法。
- parseBeanDefinitions又调用了BeanDefinitionParserDelegate中的parseBeanDefinitionElement()方法,将Element转换成了BeanDefinitionHolder。
- parseBeanDefinitionElement()中有一步操作,调用Utils将BeanDefinitionHolder中的BeanDefinition注册到DefaultBeanDefinitionDocumentReader内部的容器中。
- DefaultBeanDefinitionDocumentReader最终通过registerBeanDefinition将BeanDefinition放到了一个Map对象中,这就是对象管理的容器。