新增一个Student类
/**
* POJO: Plain Old Java Object
*/
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
编写Spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.cx.spring.kernel.lecture.bean.Student">
<property name="age" value="23"/>
<property name="name" value="zhangsan"/>
</bean>
</beans>
定义一个main方法
/*
IOC(Inverse of Control,控制反转) 本该由使用者来创建对象我们将指定资源交给工厂 此时由工厂进行创建其对应对象 将其加载到内存当中
DI (Dependency Injection,依赖注入) A中依赖B此时将A加载到IOC 此时B也得被加载到IOC 此时A才能被调用。 此时就称为依赖注入
1.需要将bean的定义信息声明在Spring的配置文件当中
2.需要通过Spring抽象出的各种Resource来指定对应的配置文件。
3.需要显示的声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
4.需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息
5.读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中
6.需要将读取器与工厂以及资源对象进行相应的关联处理。
7.工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。
Spring对应Bean管理的核心组件:
1.资源抽象ClassPathResource
2.工厂DefaultListableBeanFactory
3.配置信息读取器XmlBeanDefinitionReader (当读取器将资源读取到工厂当中 此时我们只需要跟工厂打交道)
BeanFactory 是Spring工厂 最顶层的抽象(类似Object类) 我们使用的抽象bean工厂都是直接或间接的衍生至BeanFactory
*/
public class SpringClient {
public static void main(String[] args) {
//类路径下的资源 将其具体抽象成资源对象
Resource resource = new ClassPathResource("applicationContext.xml");
//创建Bean工厂
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
//创建bean读取器
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
//将读取的资源放到defaultListableBeanFactory工厂当中
beanDefinitionReader.loadBeanDefinitions(resource);
//读取完我们需要哪个对象找工厂要
Student student = (Student) defaultListableBeanFactory.getBean("student");
System.out.println(student.getAge());
System.out.println(student.getName());
}
}
1.需要将bean的定义信息声明在Spring的配置文件当中
2.需要通过Spring抽象出的各种Resource来指定对应的配置文件。
3.需要显示的声明一个Spring工厂,该工厂用来掌控我们在配置文件中所声明的各种bean以及bean之间的依赖关系与注入关系
4.需要定义一个配置信息读取器,该读取器用来读取之前所定义的bean配置文件信息
5.读取器的作用是读取我们所声明的配置文件信息,并且将读取后的信息装配到之前所声明的工厂当中
6.需要将读取器与工厂以及资源对象进行相应的关联处理。
7.工厂所管理的全部对象装配完毕,可以供客户端直接调用,获取客户端想要使用的各种bean对象。
1.资源抽象ClassPathResource
2.工厂DefaultListableBeanFactory
3.配置信息读取器XmlBeanDefinitionReader (当读取器将资源读取到工厂当中 此时我们只需要跟工厂打交道)
IOC(Inverse of Control,控制反转) 本 该由使用者来创建对象我们将指定资源交给工厂 此时由工厂进行创建其对应对象 将其加载到内存当中=
DI (Dependency Injection,依赖注入) A中依赖B此时将A加载到IOC 此时B也得被加载到IOC 此时A才能被调用。 此时就称为依赖注入
Resource resource = new ClassPathResource("applicationContext.xml");
/**
*
为类加载器的使用创建一个新的类路径资源。前导斜杠将被删除,
因为类加载器资源访问方法将不接受它。
*
*/
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
/**
* 为类使用创建新的ClassPathResource。路径可以是相对于给定类的,
* 也可以是通过正斜杠在类路径中的绝对路径
*/
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
//底层将传过来的路径进行校正得到合法的路径
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
//得到正常使用的路径 给成员变量赋值
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
构建Resource 对象 为成员变量赋值
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
程序在实例化时。将spring提供的三个接口忽略掉,防止他们被解析,也就是说spring不希望当前工厂解析时加载到对应的接口
BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
doc
bean定义读取器的简单接口。使用资源和字符串位置参数指定加载方法。
具体的bean定义阅读器当然可以为bean定义添加额外的load和register方法,具体到bean定义格式。
请注意,bean定义读取器不必实现此接口。它只为希望遵循标准命名约定的bean定义读者提供建议。
简单来说就是读取bean的定义通过loadBeanDefinitions这个读取器最终的目的是为构建resource里的bean实例,而该实例是通过传入的BeanFactory来创建
/**
* 为新的XmlBean读取器创建新的XmlBean工厂。
*/
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);//调用父类的AbstractBeanDefinitionReaher
}
/**
为给定的bean工厂创建一个新的AbstractBeanDefinitionReader。如果传入的BeanFactory不仅实现了
BeanDefinitionRegistry接口,而且实现了ResourceLoader接口,那么它也将用作默认的ResourceLoader。
通常情况下org.springframework.context.ApplicationContext实现。
如果给定一个纯BeanDefinitionRegistry,则默认的ResourceLoader将是
PathMatchingResourcePatternResolver。
如果传入的bean factory也实现EnvironmentCapable,则此读取器将使用它的环境。
否则,读取器将初始化并使用标准环境。所有ApplicationContext实现都支持环境,
而普通的BeanFactory实现则不支持。
*/
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//工厂赋值
this.registry = registry;
// 确定要使用的ResourceLoader。
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
//如果没有定义资源加载器自定义一个类加载器加载资源
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
//如果传入的bean factory也实现EnvironmentCapable,则此读取器将使用它的环境(概要文件和属性信息)。
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
//否则,读取器将初始化并使用标准环境
this.environment = new StandardEnvironment();
}
}
多种配置信息来源的一种抽象和提取。Environment定义了Profiles的方法处理。PropertyResolver定义了Property属性相关的处理
创建读取器 spring还是会在底层判断创建资源加载器和对应的环境
beanDefinitionReader.loadBeanDefinitions(resource);
loadBeanDefinitions 做了两件事
1.对xml信息的整体解析
2,将解析完的信息放在一个bean中由工厂来进行统一管理
/**
*从指定的XML文件加载bean定义。
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//将资源编码整合成一个bean实例
return loadBeanDefinitions(new EncodedResource(resource));
}
/**
* 从指定的XML文件加载bean定义。
* @param encodedResource 编码后的资源文件
* @return 找到的bean定义数
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
//是否启用跟踪
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
//获取当前线程安全的EncodedResource集合
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
//现有资源存在的话抛异常
if (!currentResources.add(encodedResource)) {
//防止资源导入中AB互相依赖 循环导入 陷入死循环
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
//读取配置文件信息 jdk1.7提供的获取流无需关闭
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
//SAX流读取的方式将流包装
InputSource inputSource = new InputSource(inputStream);
//如果编码不为空
if (encodedResource.getEncoding() != null) {
//采用encodedResource的编码格式 解析xml
inputSource.setEncoding(encodedResource.getEncoding());
}
/*
准备工作完成
1.SAX流包装
2.SAX流编码
将SAX流和xml资源 doLoadBeanDefinitions
SAX流解析xml资源
*/
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
//threadLocal 是弱引用 使用完需要主动关闭 防止内存泄露
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
/**
*真正从指定的XML文件加载bean定义。
* @param inputSource 要从中读取的SAX输入源
* @param resource the XML文件的资源描述符
* @return 找到的bean定义数
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
/*
Document接口表示整个HTML或XML文档。
从概念上讲,它是文档树的根,提供对文档数据的主要访问。
将XML数据封装成一个Document 他表示整个HTML或XML文档
*/
Document doc = doLoadDocument(inputSource, resource);
/*
解析Document 文档数据 返回解析bean数量
*/
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
1.创建解析器类的新实例,并对其调用registerBeanDefinitions
2.注册给定DOM文档中包含的bean定义 到容器上面。由loadBeanDefinitions调用。
/**
1.创建解析器类的新实例,并对其调用registerBeanDefinitions
* 2.注册给定DOM文档中包含的bean定义 到容器上面。由loadBeanDefinitions调用。
* @param doc document对象
* @param 资源文件
* @return 找到的bean定义数
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建资源读取器
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取工厂解析之前解析的数量(其实就是看ConcurrentHashMap的size)
int countBefore = getRegistry().getBeanDefinitionCount();
//通过解析器正式开始解析
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//可能存在注解解析导致之前解析有数据 解析后解析数-解析前解析数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
在spring当中 Default开头基本都是某个接口的具体实现类 do开头为真正执行的逻辑代码
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
doc
他有个很重要的唯一方法用来想容器注册Bean
/**
*从给定的DOM文档中读取bean定义,并在给定的reader上下文中向注册表注册它们。
* @param doc the DOM document
* @param readerContext 读取器的当前上下文(包括目标注册表和正在解析的资源)
* @throws BeanDefinitionStoreException in case of parsing errors
*/
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
throws BeanDefinitionStoreException;
BeanDefinitionDocumentReader的实现类主要用来解析spring.xml里的数据,该类封装xml里所有的标签属性(一级标签)
使用委托模式和来处理 xml数据模板模式来扩展执行前后的逻辑
/**
* This implementation parses bean definitions according to the "spring-beans" XSD
* (or DTD, historically).
* Opens a DOM Document; then initializes the default settings
* specified at the {@code } level; then parses the contained bean definitions.
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获取文档元素
Element root = doc.getDocumentElement();
//开始解析 bean
doRegisterBeanDefinitions(root);
}
/**
* 在给定的根 元素中注册每个bean定义。
*/
protected void doRegisterBeanDefinitions(Element root) {
/*
任何嵌套的元素都将导致此方法中的递归。在为了正确地传播和保存default-*属性,
跟踪当前(父)委托,该委托可能为空。创建新(子)委托,其中引用了用于回退目的的父级,
然后最终复位这个。委托人返回其原始(父)引用。这种行为模拟了一堆委托,实际上并不需要一个。
*/
BeanDefinitionParserDelegate parent = this.delegate;
//采用委托模式解析
this.delegate = createDelegate(getReaderContext(), root, parent);
//delegate 如果是默认的命名空间
if (this.delegate.isDefaultNamespace(root)) {
//PROFILE_ATTRIBUTE = "profile"; 获取属性
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
//判断是否有内容
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
/*该地方用到了模板方法模式
父类规定好执行流程 具体执行逻辑由子类自由扩展 并严格遵守父类定义好的执行流程
*/
preProcessXml(root);//文档解析之前可以做的事情 可扩展
//使用委托对象去解析rootElement数据
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);//文档解析之后可以做的事情
//委托对象重新赋值
this.delegate = parent;
}
封装一级标签下对应的子标签属性和对应的解析方法 将解析的数据放在holder持有类当中,该类是一个委托类
解析文档中根级别的元素:“import”、“alias”、“bean”。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 判断是否是命名空间之内的
if (delegate.isDefaultNamespace(root)) {
//包含此节点的所有子节点的节点列表。如果没有子节点,则这是一个不包含节点的NodeList。
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
//获取子节点
Node node = nl.item(i);
//判断是否是Element元素 可能存在注释 注释标签不属于Element
if (node instanceof Element) {
Element ele = (Element) node;
//判断是否是命名空间之内的
if (delegate.isDefaultNamespace(ele)) {
//真正完成对元素解析 由委托对象进行解析
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
因为“import”、“alias”、“bean”。 存在子节点 所以要用于区分 每个子节点下的数据分别进行解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//import标记 加载导入的另一个bean文件
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
//import 解析子节点数据 其他同理
importBeanDefinitionResource(ele);
}
//alias标签 处理别名的注册
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//bean标签 处理bean标签的注册
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//beans 如果嵌套Beans 重新走一遍流程
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// 重新走一遍流程 执行递归
doRegisterBeanDefinitions(ele);
}
}
我们具体看bean的处理方案
完成两件事
/**
完成两件事情
* 1.处理给定的bean元素,解析bean定义
* 2.并将其注册到工厂中。
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/*获取持有对象 里面封装了《Bean》BeanDefinition(标签节点)
,bean的id值,以及对应的别名数组
一个BeanDefinition 对应一个bean标签
*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
//注册到工厂当中
if (bdHolder != null) {
// 加工包装 解析自定的标签属性 持有对象 返回最终的持有对象
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 最终将加工的持有对象注册到Bean工厂当中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
解析XMLBean定义的节点
/**
* Parses the supplied {@code } element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
//获取id 和name属性值
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//获取别名
List<String> aliases = new ArrayList<>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//beanName =id值
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//获取beanDefinition 对象 里面封装了当前bean的所有信息
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//beanDefinition 解析的标签下所有标签数据,id对应的name 别名数组
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
/**
* Parse the bean definition itself, without regard to name or aliases. May return
* {@code null} if problems occurred during the parsing of the bean definition.
*/
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
/*
解析bean的一些属性标签的一些信息和bean节点之下的标签对应属性的解析
*/
try {
///获取beanDefinition 对象 里面只封装了class对象或者 当前bean的二进制名称
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析各种属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//构造器注入bean的解析
parseConstructorArgElements(ele, bd);
//Property属性注入解析
parsePropertyElements(ele, bd);
//setter注入解析
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
//返回装配了xmlBeans标签配置信息的持有对象
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
/**
* Create a new GenericBeanDefinition for the given parent name and class name,
* eagerly loading the bean class if a ClassLoader has been specified.
* @param parentName the name of the parent bean, if any
* @param className the name of the bean class, if any
* @param classLoader the ClassLoader to use for loading bean classes
* (can be {@code null} to just register bean classes by name)
* @return the bean definition
* @throws ClassNotFoundException if the bean class could not be loaded
*/
public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
//GenericBeanDefinition 描述bean定义的一些信息
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
//如果类加载器存在 就直接加载对应二进制name 获取当前beanclass对象
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
//指定bean的二进制名 与class对象公用一个字段
bd.setBeanClassName(className);
}
}
return bd;
}
不管是name全称还是对应的class对象 都能唯一确定实例化对象 所有在使用的时候一定会根据这个字段做判断判断他是字符串还是class对象
将持有对象和 当前读取器对应的工厂传入
/**
* 向给定的bean工厂注册给定的bean定义。
* @param definitionHolder bean定义,包括名称和别名
* @param registry 要注册的bean工厂
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
//获取bean的名字
String beanName = definitionHolder.getBeanName();
// 将对应的bean注册到工厂上
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
//注册bean名称的别名(如果有的话)。
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
如上图可知在加载到bean工厂之前持有对象已经封装了装载《beans》标签的所有子标签的配置类,得到了beans的唯一id 的name值,以及对应的别名集合
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//bean的验证
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
/**
ConcurrentHashMap中获取持有对象
spring是拿beanname 做key 持有对象做value将数据存在 ConcurrentHashMap中
jdk1.5之前使用的hashMap
*/
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
//判断是否存在同id的BeanDefinition
if (existingDefinition != null) {
//判断相同beanId值(默认是覆盖对应bean 如果未开启复写则抛异常)
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
//若已存在的和需要装配的bean不同
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//如果不存在上述情况 加载到工厂当中(id做key,beanDefinition做value)
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//检查这个工厂的bean创建阶段是否已经开始,即是否有任何bean同时被标记为已创建。
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;
removeManualSingletonName(beanName);
}
}
else {
//反之
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
//重置当前的bean定义
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
该map是DefaultListbleBeanFactory工厂的一个属性。此时将bean的唯一id做key ,解析bean BeanDefinition 做value 存储的工厂当中当中
此时我们spring将读取的资源放到defaultListableBeanFactory工厂当中底层源码流程解析完毕