spring
前述:spring源码环境搭建以及源码下载在文章后方有链接,可自行参考搭建,这里只是对加载过程做一个解析,spring全家桶远不止这些东东,感兴趣的小伙伴可以去官网看一下,本文将以源码加注释的方式进行过程解析,带你了解spring中bean到底是如何一步步加载完成
了解重点:bean的生命周期、加载过程
最终目的:学习spring源码短期内不对对你的技术有太大提升,可能只是了解到漂亮的代码是如何写出来,为何别人写代码就不是简单的接口加上无限的if-else,所以加强基础知识的学习、多去思考如何优化逻辑才会有效提高编程效率。spring源码经历了多年的沉淀,没有一年半载很难搞透彻,所以什么手撕源码还是要慎重,大部分源码博客都只是告诉你源码的执行过程,不会告诉你原理和如何去改造,本文也是如此
本文目录:也就是bean加载的大致过程
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
this(path, (ClassLoader) null);
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
/** 对父类 DefaultListableBeanFactory进行实例化 */
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
/**
* Create a new DefaultListableBeanFactory.
*/
public DefaultListableBeanFactory() {
super();
}
继续跟踪到AbstractAutowireCapableBeanFactory类下
/**
* Create a new AbstractAutowireCapableBeanFactory.
*/
public AbstractAutowireCapableBeanFactory() {
super();
/**ignoreDependencyInterface方法注解
* 作用:假如A中有属性B,初始化A时会先对B进行初始化,这是spring的一个重要特性
* 会A加载时自动忽略给定的依赖接口
* */
ignoreDependencyInterface(BeanNameAware.class);
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
this.reader.loadBeanDefinitions(resource);
注:
//DefaultListableBeanFactory--整个bean加载的核心部分,是spring注册以及加载bean的默认实现,主要用于bean注册后的处理
public class XmlBeanFactory extends DefaultListableBeanFactory {
//XmlBeanFactory 与父类的区别在于实现了自定义的xml读取器XmlBeanDefinitionReader,使用reader属性对资源文件进行读取和注册
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
/** 使用EncodedResource对resource进行封装,作用是对资源文件的编码进行处理
* */
return loadBeanDefinitions(new EncodedResource(resource));
}
EncodedResource只是对属性进行封装,不做其他处理
private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
super();
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.encoding = encoding;
this.charset = charset;
}
继续回到资源加载的核心部分
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);
}
/** 通过属性来记录已经加载的文件 **/
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
/**从resource中获取对应的inputStream并构造inputResource */
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
/** 以上只是对resource参数进行封装,考虑到其编码问题,下面进入核心处理部分**/
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()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
步骤分解:
private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"){
@Override
protected Set<EncodedResource> initialValue() {
return new HashSet<>(4);
}
};
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
/** 以上只是对resource参数进行封装,考虑到其编码问题,下面进入核心处理部分**/
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
它做的事情大致如下:主要包括两步
/** 1.获取对XMl文件的验证格式xsd或dtd
* 2.加载xml封装为document
* 3.根据返回的document封装bean**/
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
/** 这里解析一下getEntityResolver是做什么的,作用是提供给项目一个寻找dtd验证模式的方法
原始的是根据路径去下载验证文件,为避免网络的影响,在本地存贮一个验证文件 **/
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
模式验证:其实就是一行一行的读取文件,获取其中是否包含某个关键词(doctype)
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
/** 如果已经指定验证模式,则使用指定的验证模式,没有指定则使用自动的 **/
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
/** 自动检测验证模式功能 **/
int detectedMode = detectValidationMode(resource);
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
// Hmm, we didn't get a clear indication... Let's assume XSD,
// since apparently no DTD declaration has been found up until
// detection stopped (before finding the document's root tag).
return VALIDATION_XSD;
}
验证的具体过程:detectValidationMode方法进入
try {
inputStream = resource.getInputStream();
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
"Did you attempt to load directly from a SAX InputSource without specifying the " +
"validationMode on your XmlBeanDefinitionReader instance?", ex);
}
try {
return this.validationModeDetector.detectValidationMode(inputStream);
}
detectValidationMode进入:只是指定最后的验证模式
public int detectValidationMode(InputStream inputStream) throws IOException {
// Peek into the file to look for DOCTYPE.
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) {
isDtdValidated = true;
break;
}
if (hasOpeningTag(content)) {
// End of meaningful data...
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
}
catch (CharConversionException ex) {
// Choked on some character encoding...
// Leave the decision up to the caller.
return VALIDATION_AUTO;
}
finally {
reader.close();
}
}
到此结束:doLoadDocument
下面分析其中的一个类:getEntityResolver(作用:尝试去下载验证文件或者加载本地验证文件)
protected EntityResolver getEntityResolver() {
if (this.entityResolver == null) {
// Determine default EntityResolver to use.
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
this.entityResolver = new ResourceEntityResolver(resourceLoader);
}
else {
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
以DelegatingEntityResolver为例进入方法:做的什么???
public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
this.dtdResolver = new BeansDtdResolver();
this.schemaResolver = new PluggableSchemaResolver(classLoader);
}
实现类:public class BeansDtdResolver implements EntityResolver;指定了验证文件的两个重要属性
实例化了两个解析器,一个dtd文件解析器,一个模式解析器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PwUdt5Ik-1629963237562)(C:\Users\15515\AppData\Roaming\Typora\typora-user-images\image-20210728175913418.png)]
@Override
@Nullable
public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Trying to resolve XML entity with public ID [" + publicId +
"] and system ID [" + systemId + "]");
}
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
int lastPathSeparator = systemId.lastIndexOf('/');
int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
if (dtdNameStart != -1) {
String dtdFile = DTD_NAME + DTD_EXTENSION;
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isTraceEnabled()) {
logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (FileNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
}
}
}
}
// Fall back to the parser's default behavior.
return null;
}
/*把文件转化为document对象后开始bean的注册以及加载
*/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
/** 使用DefaultBeanDefinitionDocumentReader来实例化BeanDefinitionDocumentReader对象 **/
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
/** 这里去除了之前设置环境变量的一步 **/
/** 记录之前BeanDefinition加载的个数 **/
int countBefore = getRegistry().getBeanDefinitionCount();
/** 加载及注册bean **/
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
/** 记录本次加载的bean个数 **/
return getRegistry().getBeanDefinitionCount() - countBefore;
}
开始对配置文件属性进行解析,包括很多标签中声明的属性(注:此版本源码与pdf中有所不同,只是改变了写法而已)
/* doc.getDocumentElement()返回Element root对象
* 本方法就是提取root作为参数继续BeanDefinition的注册
*/
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
/** 真正对文件解析属性注册bean的开始 **/
doRegisterBeanDefinitions(doc.getDocumentElement());
}
解析方法
protected void doRegisterBeanDefinitions(Element root) {
// Any nested elements will cause recursion in this method. In
// order to propagate and preserve default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//对profile进行处理解析,可了解profile属性的作用以及使用,从根节点依次开始获取属性
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
/** preProcessXml、postProcessXml两个方法是空的,作用是解析bean前预处理、解析后处理,根据面向对象设计原则,一个类要么面向继承设计,要么用final修饰
* 这里是交给子类来实现的 **/
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
以下是对上面的解析过程parseBeanDefinitions进行拆解分步解析:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
/** 获取是否为自定义命名空间,默认的和非默认的使用不同的处理方式 因为spring xml中bean的声明方式有两种
* 1. 这一种是spring默认的
* 2. **/
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(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {/** 默认标签的解析 **/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//对import标签解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}//对ALIAS标签解析
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);
}
}
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);
}
}
进入倒数第二个if中,以此为例进行分析 processBeanDefinition(ele, delegate);
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/** 对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/** 默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 **/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.对解析后的bdHolder对象进行注册,属性解析完后就是注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
/** 发出相应事件,告诉监听器该bean已经加载完毕 **/
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
下面又是对上面几个过程进行解析:
/**
* 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) {
String id = ele.getAttribute(ID_ATTRIBUTE);
/** 获取name属性,此处可以参考源码中的string转数组再转list写法 **/
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));
}
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);
}
/** 检测bean没有指定beanName,那么就使用默认规则为bean生成beanName **/
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;
}
}
/** 将获取到的全部信息封装到BeanDefinitionHolder中 **/
String[] aliasesArray = StringUtils.toStringArray(aliases);
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.
* 解析除name以外的其他属性
* 这里可以进入AbstractBeanDefinition类对象中看一下拥有的具体属性
* GenericBeanDefinition只是对AbstractBeanDefinition的子类实现,大部分属性都保存在父类属性中
*/
@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);
}
try {
/** 创建可以承载属性的AbstractBeanDefinition类型的GenericBeanDefinition **/
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
/** 上面获取了一个bean的信息后封装在对象里,以下均为解析各种属性 **/
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
/** 解析子元素meta属性 **/
parseMetaElements(ele, bd);
/** 获取器注入,通过声明方法返回某一种属性的bean,具体作用参考54-57 **/
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
/** 可以在运行时用新的方法替换原有的方法 参考57-58 **/
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
/** 解析构造函数 **/
parseConstructorArgElements(ele, bd);
/** 解析子元素property **/
parsePropertyElements(ele, bd);
/** 对于qualifier元素的获取 **/
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
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;
}
后面也是对各种属性的解析过程,就不再赘述,进入下一步,走了这么远,是不是都快忘记是从哪个方法进入的了?上面只是对原来此处的第一步,下面进入第二步
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/** 第一步:对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
*
* > > 就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.对解析后的bdHolder对象进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
/** 发出相应事件,告诉监听器该bean已经加载完毕 **/
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
进入第二步方法体:第一处方法中调用了第二处
/**
* Decorate the given bean definition through a namespace handler, if applicable.
* @param ele the current element
* @param originalDef the current bean definition
* @return the decorated bean definition
* 第三个属性本处设置为null,一般传入的是父标签元素,目的是为了在子元素没有定义scope范围的情况下,默认使用父元素的范围
*/
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}
/**
* Decorate the given bean definition through a namespace handler, if applicable.
* @param ele the current element
* @param originalDef the current bean definition
* @param containingBd the containing bean definition (if any)
* @return the decorated bean definition
*/
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = originalDef;
// Decorate based on custom attributes first.
/** 遍历是否有需要修饰的属性 ,可进入decorateIfRequired方法具体了解修饰的过程**/
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
//第三步:下面会进入本方法体中了解一下
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// Decorate based on custom nested elements.
/** 遍历所有的子节点,看是否有需要修饰的属性 **/
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
进入上述第三步:
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
/** 获取自定义标签的命名空间,若非默认则进行装饰 **/
String namespaceUri = getNamespaceURI(node);
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
/** 根据命名空间找到相应的处理器并进行修饰**/
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
解析和装饰属性的工作已经完成,下面就是进行bean的注册了,也就是所谓的第三步
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/** 第一步:对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
*
* > > 就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 第三步:Register the final decorated instance.对解析后的bdHolder对象进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
/** 发出相应事件,告诉监听器该bean已经加载完毕 **/
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
进入第三步:通过bean name注册和通过别名注册
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
/** 第一步:使用bean name做唯一标识注册 ,他做的事情其实类似将beanDefination 作为value,bean-name作为key放入map中,但不止这些**/
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
/** 注册所有的别名,若别名与bean name相同,则不需要处理,删除原有的所有别名
* 覆盖处理需要用户进行处置
* 循环检查 ,最后进行注册**/
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
那么第一步还做了什么事情呢?
@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 {
/** 注册前的最后一次校验,不同于之前的xml校验
* 主要是对AbstractBeanDefinition中的MethodOverride属性进行校验
* 检验MethodOverride是否与工厂方法并存或者对应的MethodOverride方法根本就不存在 **/
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
/** 如果对应的beanName已经被注册并且配置不允许被覆盖,则抛出异常 **/
if (existingDefinition != null) {
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 + "]");
}
}
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 + "]");
}
}
/** 加入map缓存并对之前的缓存进行清理 **/
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
/** beanDefinitionMap作为全局变量,肯定存在并发问题 **/
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)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
别名的注册过程,跟beanname的注册过程很类似
@Override
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
/** 如果bean name与别名相同则不再记录,删除别名 **/
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
}
}
else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
/** 如果别名不允许被覆盖,则抛出异常 **/
if (!allowAliasOverriding()) {
throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
name + "': It is already registered for name '" + registeredName + "'.");
}
if (logger.isDebugEnabled()) {
logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
registeredName + "' with new target name '" + name + "'");
}
}
/** 如果A->B存在,再出现A->B->C则抛出异常 **/
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
}
}
}
}
以上就是对bean标签的解析,最后回归到开始的地方如下图,但是当初我们提到过,bean的注册包括对import标签、bean标签、beans标签、alias标签的解析,所以上面只是第一步,在spring bean加载过程2中,我们将进行后续的分解
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/** 第一步:对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
*
* > > 就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 第三步:Register the final decorated instance.对解析后的bdHolder对象进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
/** 发出相应事件,告诉监听器该bean已经加载完毕,其实就是将监听逻辑注册进监听器,没有进行其他特殊处理 **/
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
了各种属性id、name等 重点进入了解 **/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
/** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
*
* > > 就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 第三步:Register the final decorated instance.对解析后的bdHolder对象进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
/** 发出相应事件,告诉监听器该bean已经加载完毕,其实就是将监听逻辑注册进监听器,没有进行其他特殊处理 **/
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}