`
游伯度
  • 浏览: 22009 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Spring IOC - BeanDefinition注册

阅读更多

上次分享中,提到了 Spring 把查找出来的资源加载解析成为 Document 对象,供后面的 BeanDefinition 注册使用。本次分享,就来看看 BeanDefinition 是如何注册的,以及他注册到什么地方。

 

1. 分析源码了解 BeanDefinition 的注册过程

  

1.1org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建 BeanDefinitionDocumentReader,默认创建是 DefaultBeanDefinitionDocumentReader
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	documentReader.setEnvironment(this.getEnvironment());
	int countBefore = getRegistry().getBeanDefinitionCount();
	// resource 其实就是 ApplicationContext 实例
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}
// 你可以通过配置 documentReaderClass 属性来改变 BeanDefinitionDocumentReader 的实例
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
	return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
// 创建 XmlReaderContext 传递到 documentReader 上
protected XmlReaderContext createReaderContext(Resource resource) {
	if (this.namespaceHandlerResolver == null) {
		this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
	}
	// resouce 等信息设置到上下文中
	return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
			this.sourceExtractor, this, this.namespaceHandlerResolver);
}

通过上面的方法,初始准备了解析 Bean 定义需要的解析环境,把相关的解析需用的参数设置完成。其中有很重要的命名空间处理器(NamespaceHandlerResolver)会在后续的分享中讲解。

 

 

1.2 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

 

doRegisterBeanDefinitions方法是被registerBeanDefinitions调用的,完成注册工作转交给BeanDefinitionParserDelegate 的工作。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	 // 设置上下文
	this.readerContext = readerContext;

	logger.debug("Loading bean definitions");
	// 获取 Document 根元素
	Element root = doc.getDocumentElement();

	// 执行注册操作
	doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
	String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
	// 解析 profile 属性,判断是否需要注册此资源文件(spring3.0的新属性)
	if (StringUtils.hasText(profileSpec)) {
		Assert.state(this.environment != null, "environment property must not be null");
		String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		if (!this.environment.acceptsProfiles(specifiedProfiles)) {
			return;
		}
	}
	// 创建 BeanDefinitionParserDelegate,真正做解析工作的类实例
	// any nested <beans> elements will cause recursion in this method. In
	// order to propagate and preserve <beans> 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;
	// 在实例化的同时,需要检查 Bean 上面的初始化配置是否正确
	// BeanDefinitionParserDelegate#initDefaultsElement, BeanDefinitionParserDelegate)
	this.delegate = createHelper(readerContext, root, parent);

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

	this.delegate = parent;
}

 

1.3 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

// 解析 Bean 定义的根节点,包含 import, alias, bean。
// Root 是解析的DOM根节点
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	// 如果root 节点的namespace是空,或者是 http://www.springframework.org/schema/beans 
	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;
				// 和root节点的判断方式相同,如果是默认命名空间
				if (delegate.isDefaultNamespace(ele)) {
					parseDefaultElement(ele, delegate);
				}
				// 非默认命名空间,自定义节点
				else {
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	// 其他情况,说明是自定义节点
	else {
		delegate.parseCustomElement(root);
	}
}

 先看看默认命名空间的元素解析的入口:

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);
	}
	// 如果是 bean 元素
	else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
		processBeanDefinition(ele, delegate);
	}
	// 如果是嵌套的 beans 元素,递归解析
	else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
		// recurse
		doRegisterBeanDefinitions(ele);
	}
}

 深入看看里面的具体实现,如果不关心这个里面的细节可以选择跳过。

/**
 * import 元素解析,根据配置的 resource 属性,再一次从资源查找入手,进行导入 bean 定义解析
 * Parse an "import" element and load the bean definitions
 * from the given resource into the bean factory.
 */
protected void importBeanDefinitionResource(Element ele) {
	// 获取 resource 属性
	String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
	if (!StringUtils.hasText(location)) {
		getReaderContext().error("Resource location must not be empty", ele);
		return;
	}

	// Resolve system properties: e.g. "${user.dir}"
	// 处理系统属性
	location = environment.resolveRequiredPlaceholders(location);

	// 记录真实的资源(用表达式配置的资源可能出现多个)
	Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

	// 判断是否是绝对路径
	// Discover whether the location is an absolute or relative URI 
	boolean absoluteLocation = false;
	try {
		absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
	}
	catch (URISyntaxException ex) {
		// cannot convert to an URI, considering the location relative
		// unless it is the well-known Spring prefix "classpath*:"
	}

	// Absolute or relative?
	// 如果是绝对路径,直接解析对应绝对路径的 Bean 定义资源就可以了
	if (absoluteLocation) {
		try {
			// 这个方法在前面资源装载中已经分享过, AbstractBeanDefinitionReader#loadBeanDefinitions(String, Set<Resource>) 
			int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
			if (logger.isDebugEnabled()) {
				logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
			}
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error(
					"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
		}
	}
	// 相对路径
	else {
		// No URL -> considering resource location as relative to the current file.
		try {
			int importCount;
			// 如果资源支持创建相对路径,则创建。
			Resource relativeResource = getReaderContext().getResource().createRelative(location);
			// 判断如果资源存在,进行解析
			if (relativeResource.exists()) {
				importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
				actualResources.add(relativeResource);
			}
			// 如果不存在,在拼一下绝对路径,进行解析。如果此时无法查找到资源,就会抛异常了
			else {
				String baseLocation = getReaderContext().getResource().getURL().toString();
				importCount = getReaderContext().getReader().loadBeanDefinitions(
						StringUtils.applyRelativePath(baseLocation, location), actualResources);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
			}
		}
		catch (IOException ex) {
			getReaderContext().error("Failed to resolve current resource location", ele, ex);
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
					ele, ex);
		}
	}
	Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
	// 通知 import 元素已经解析完毕
	getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}

/**
 * 处理别名,或者说叫注册别名
 * Process the given alias element, registering the alias with the registry.
 */
protected void processAliasRegistration(Element ele) {
	String name = ele.getAttribute(NAME_ATTRIBUTE);
	String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
	boolean valid = true;
	if (!StringUtils.hasText(name)) {
		getReaderContext().error("Name must not be empty", ele);
		valid = false;
	}
	if (!StringUtils.hasText(alias)) {
		getReaderContext().error("Alias must not be empty", ele);
		valid = false;
	}
	if (valid) {
		try {
			// 注册到别名Map中,后面会再次提到此处的使用
			getReaderContext().getRegistry().registerAlias(name, alias);
		}
		catch (Exception ex) {
			getReaderContext().error("Failed to register alias '" + alias +
					"' for bean with name '" + name + "'", ele, ex);
		}
		getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
	}
}

/**
 * 处理 bean 元素,本身不处理,交给了 BeanDefinitionParserDelegate 
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 解析Bean定义,存放在 BeanDefinitionHolder 中
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 判断是否需要装饰 BeanDefinition,如果需要装饰,返回装饰后的 Bean 定义
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// Register the final decorated instance.
			// 注册 Bean 到 Factory
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// Send registration event.
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

BeanDefinitionHolder

BeanDefinitionHolder  不仅包含了 BeanDefinition 信息,同时记录了对应的Bean的名称以及别名信息。

 

1.4 org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element, BeanDefinition)

BeanDefinitionParserDelegate解析 Bean 定义的地方。

 

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
	// id 属性
	String id = ele.getAttribute(ID_ATTRIBUTE);
	// name 属性,可以用“,;”分割,得到别名定义
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

	List<String> aliases = new ArrayList<String>();
	if (StringUtils.hasLength(nameAttr)) {
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}

	// bean 的唯一名称是定义的 id 属性,不是name
	// 如果当没有定义 id 属性时,从定义的别名中取得一个
	String beanName = id;
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		beanName = aliases.remove(0);
		if (logger.isDebugEnabled()) {
			logger.debug("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}

	// 如果不是嵌套bean,验证 beanName 唯一性
	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}

	// 解析 bean 属性值以及子元素标签
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		if (!StringUtils.hasText(beanName)) {
			try {
				// 如果是内部 bean,创建内部 bean 名称
				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.isDebugEnabled()) {
					logger.debug("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);
		// 返回 BeanDefinitionHolder
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

	return null;
}
 
1.5 org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#decorateIfRequired

如果自定义的 schema 来进行 Bean 解析,调用对应的 NameSpaceHandler 进行装饰。具体的自定义方式、方法、原理将在下次分享中分享。

private BeanDefinitionHolder decorateIfRequired(
		Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
	// 获取对应的命名空间,如果不是 Spring 定义的默认命名空间,进行装饰处理
	String namespaceUri = getNamespaceURI(node);
	if (!isDefaultNamespace(namespaceUri)) {
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler != null) {
			return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
		}
		else if (namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
			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;
}

 

 

1.6 org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(Element, BeanDefinition)

 

解析自定义 schema 中的 bean 元素,进行自定义解析

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	// 获取对应的命名空间解析处理器来进行解析处理
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	// 解析的实现中选择是否需要把bean定义注册到 Factory 中
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

 

1.7 org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition

 

此法静态方法,负责把解析好的 Bean 定义注册到容器中

public static void registerBeanDefinition(
		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {

	// Register bean definition under primary name.
	String beanName = definitionHolder.getBeanName();
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// Register aliases for bean name, if any.
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String aliase : aliases) {
			registry.registerAlias(beanName, aliase);
		}
	}
}

 

 

一般的容器都会继承 DefaultListableBeanFactory,我们看看 Bean 注册是怎么实现的:

org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
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 {
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}

	synchronized (this.beanDefinitionMap) {
		// 所有解析好的 Bean 定义都会放在 beanDefinitionMap 中
		Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		// 如果可以通过 Bean 名称获取到 Bean 定义,那么需要判断是否允许覆盖
		if (oldBeanDefinition != null) {
			if (!this.allowBeanDefinitionOverriding) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
		}
		else {
			this.beanDefinitionNames.add(beanName);
			this.frozenBeanDefinitionNames = null;
		}
		// 注册 Bean 定义到 beanDefinitionMap 中
		this.beanDefinitionMap.put(beanName, beanDefinition);

		resetBeanDefinition(beanName);
	}
}

 

综上,所有解析好的 Bean 定义被封装在 BeanDefinitionHolder 中,让后经过各种判断最终放在了 DefaultListableBeanFactory 的 benDefinitionMap 中。至此,Bean 解析和注册完成,为后续的依赖注入提供了数据基础。下次分享还是要深化这个解析过程,讲述自定义 schema 解析Bean过程。

 

OK,今天就到这里吧。

分享到:
评论

相关推荐

    撸一撸Spring Framework-IoC-BeanDefinition(csdn)————程序.pdf

    撸一撸Spring Framework-IoC-BeanDefinition(csdn)————程序

    尚硅谷]_佟刚_Spring IOC 容器中 Bean 的生命周期.pdf

    1、&lt;bean&gt;标签主要用来进行Bean定义; 2、alias用于定义Bean别名的;...这两种方式都是通过调用Bean Definition Reader 读取Bean定义,内部实现没有任何区别。标签可以放在下的任何位置,没有顺序关系。

    Spring中眼花缭乱的BeanDefinition.docx

    为什么要读Spring源码,...看几篇博客,对照着看看源码,应该就没什么问题了,但是如果想真正的玩懂Spring,需要花的时间真的很多,需要你沉下心,从最基础的看起,今天我们就来看看Spring中的基础——BeanDefinition。

    SpringFramework常见知识点.md

    (BeanDefinition) - bean的作用域有哪些? - Spring 的扩展点主要有哪些? - Spring如何解决循环依赖? - 事务的传播行为是什么?有哪些? - 什么是AOP? - AOP的组成元素和概念有哪些? - AOP实现方式有哪些? - ...

    spring第二天.pdf

    7. 可以自主完成阅读Spring框架中BeanDefinition注册流程的源码 8. 可以自主完成阅读Spring框架中Bean实例创建流程的源码 9. 可以自主完成阅读Spring框架中依赖注入流程的源码 10. 可以确定aop流程的源码阅读入口

    tiny-spring-practice:实践tiny-spring,手写Spring两大核心功能:IOC和AOP

    一起来学tiny-spring 目录 step9-用Annotation方式来实现运行时注入bean 【Spring之AOP功能】 背景 最近想深入学习一下Spring的两大核心...BeanDefinition:用于保存bean对象以及其他额外的信息。 BeanFactory:维护一

    学习spring ioc和aop

    spring 核心功能演示项目 1. applicationContext xml方式和注解方式配置 2. pring bean循环依赖。 3. spring bean 启动顺序。...4. BeanDefinition编程式注入到容器。 5. spring aop 打印 6. spring 事务

    Spring原理篇.xmind

    包括内容:Spring体系结构、Spring重要接口讲解(BeanFactory继承体系、BeanDefinition继承体系、ApplicationContext继承体系)、IOC/DI(容器初始化流源码分析)、AOP原理(解析流程,代理流程,执行流程)、事务...

    spring-framework-reference-4.1.2

    Aliasing a bean outside the bean definition ................................................ 28 Instantiating beans .......................................................................................

    spring-framework-reference4.1.4

    Aliasing a bean outside the bean definition ................................................ 28 Instantiating beans .......................................................................................

    tiny-spring:模仿spring原始代码建造自己的框架

    小弹簧第一部分:IoC容器1.step1-最...注入beanBeanDefinition beanDefinition = new BeanDefinition ( new HelloWorldService ());beanFactory . registerBeanDefinition( " helloWorldService " , beanDefinition);//

    Spring原理解析-BeanFactory—容器加载过程解析

    Spring的IOC容器—BeanFactory—容器加载过程解析容器加载DefaultListableBeanFactory类介绍BeanFactory接口介绍BeanDefinition接口介绍BeanDefinitionRegistry接口介绍如何解析xml文件 容器加载 ...

    IOC容器初始化过程

    IOC容器的初始化分为三个过程实现:第一个过程是Resource资源定位。这个Resouce指的是BeanDefinition的资源定位。...第三个过程是向IOC容器注册这些BeanDefinition的过程,这个过程就是将前面的BeanDefit

    spring源代码解析

    //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws...

    Spring.3.x企业应用开发实战(完整版).part2

    5.1.2 BeanDefinition 5.1.3 InstantiationStrategy 5.1.4 BeanWrapper 5.2 属性编辑器 5.2.1 JavaBean的编辑器 5.2.2 Spring默认属性编辑器 5.2.3 自定义属性编辑器 5.3 使用外部属性文件 5.3.1 使用外部属性文件 ...

    Spring3.x企业应用开发实战(完整版) part1

    5.1.2 BeanDefinition 5.1.3 InstantiationStrategy 5.1.4 BeanWrapper 5.2 属性编辑器 5.2.1 JavaBean的编辑器 5.2.2 Spring默认属性编辑器 5.2.3 自定义属性编辑器 5.3 使用外部属性文件 5.3.1 使用外部属性文件 ...

    minisp代码.zip

    两个用于封装数据的类:BeanDefinition,ObjectFactory 一个工具类:BeanDefinitionReaderUtils 还剩余三个类实现了功能逻辑:DefaultListableBeanFactory,AnnotatedBeanDefinitionReader,...

    thinking-in-spring:学春天

    BeanDefinition的注册 XML格式 注解BeanDefinitionRegistryDemo @豆 @零件 @进口 Java API配置元信息 Bean实例化 常规方法 非常规方法 Bean的初始化 顺序:@PostConstruct&gt; InitializingBean#afterPropertiesSet...

    dpspring:手写简单框架

    dpspring 手写弹簧简单框架 豆子 ApplicationContext 简单料理界... beanDefinition--&gt; 保存在内存中 4.初始化ioc容器,并且实例化对象 ---&gt;beanWrapper:原生对象和代理对象关联关系 5.完成di 6.handlermapping

Global site tag (gtag.js) - Google Analytics