Spring 源码阅读(IOC容器)-容器启动2 2.2.3 资源定位、解释
2.2.3.1 资源定位加载与容器的关系
loadBeanDefinitions方法主要是加载BeanDefinition,而BeanDefinition的定义是来自于一组资源的,要加载BeanDefinition,Spring首先要加载、解释这些资源,资源的定位、加载由ResourceLoader与ResourcePatternResolver负责。
在loadBeanDefinitions方法分析之前,我们先来了解下容器与ResourceLoader之间的联系。ResourceLoader是资源加载器接口;ResourcePatternResolver是资源模式解释器接口,它把一个定位模式(例如,ant样式模式)转变为Resource对象; ResourcePatternResolver扩展自ResourceLoader,因此也可以说一个ResourcePatternResolver的实现在同时具备资源模式解释的同时,也具备资源的加载功能呢(关于继承结构参见图1)。
那么容器与ResourceLoader、ResourcePatternResolver在结构上有什么联呢?
首先,看一下
接口ApplicationContext与ResourcePatternResolver的关系:
ResourcePatternResolver {
……
}
从代码中可以看到,任何的上下文容器都应该支持资源模式的解释的功能,即能够解释ant-style的资源定义。我们看到了应用上下文接口声明支持资源模式的解释功能,那么具体的应用上下文容器是如何实现资源的定位以及资源模式的解释的呢?
接下来,我们看一下抽象类AbstractApplicationContext与ResourceLoader、ResourcePatternResolver的关系:
extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
//意味着FileSystemXmlApplicationContext在创建时,就已经拥有resolver实例,见灰色部分
pivate ResourcePatternResolver resourcePatternResolver;
public AbstractApplicationContext(ApplicationContext parent) {
this.parent = parent;
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
//解释返回资源的功能不是其自身实现,而是通过调用resourcePatternResolver提供
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}
由代码可以看出,资源模式解释器在容器创建时就已经创建,资源模式解释器由PathMatchingResourcePatternResolver担当。AbstractApplicationContext继承于DefaultResourceLoader(ResourceLoader的默认实现),因此AbstractApplicationContext也具备了资源加载的功能。同时ApplicationContext扩展了ResourcePatternResolver接口,所以ApplicationContext的实现类对外表现的Loader应该为ResourcePatternResolver。通俗来讲,就是说容器具备资源模式解释的功能,并能对一资源位置进行加载,参看图-1理解一下。
知道了容器与ResourceLoader之间的联系,我们继续loadBeanDefinitions方法的分析。
2.2.3.2 loadBeanDefinitions方法分析
我们在上一节refreshBeanFactory方法中知道,内部工厂初始化的最后一步是加载BeanDefinition。loadBeanDefinitions方法是由抽象AbstractXmlApplicationContext
实现的。它在这里主要做了以下功能:把加载Definition(从字面上就能看出,其是对xml中的bean的定义)的工作委托给XmlBeanDefinitionReader,XmlBeanDefinitionReader来进行资源的定位,资源的加载。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
/** *//**这里的beanFactory是以BeanDefinitionRegistry的角色作为参数传入到XmlBeanDefinitionReader中的,由于DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,因此,beanFactory具备了BeanDefination的注册功能*/
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//为reader设置resourceloader,参看类图DefaultListableBeanFactory继承自DefaultResourceLoader
beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
/** */ /**从下段代码可以看出,虽然容器具备资源的加载的功能,但是spring并没有在容器类中直接处理资源加载的工作,而是把这项工作委托给XmlBeanDefinitionReader。XmlBeanDefinitionReader是XML bean definitions的reader,它把实际的XML文档读取任务交给了DefaultBeanDefinitionDocumentReader来完成.*/
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//由XmlBeanDefinitionReader来加载beanDefinition
reader.loadBeanDefinitions(configLocations);
}
}
/** */ /***以下方法来自于AbstractBeanDefinitionReader,该类是XmlBeanDefinitionReader的超类***/
// 由一组指定的资源位置,加载资源
public int loadBeanDefinitions(String[] locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (int i = 0; i < locations.length; i++) {
counter += loadBeanDefinitions(locations[i]);
}
return counter;
}
// 加载特定资源位置下的资源
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
……
if (resourceLoader instanceof ResourcePatternResolver) {
try { //这里进行资源位置解释成资源(Resource)关于资源定位解释成资源,请参看后面的“资源定位分析”
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (int i = 0; i < resources.length; i++) {
actualResources.add(resources[i]);
}
}
return loadCount;
}
catch (IOException ex) {
…….
}else{
…….
}
}
/** *//**以下方法来自XmlBeanDefinitionReader**/
//加载指定的resource,由上面的方法调用,主要对resource进行编码处理
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
//加载经过编码后的Resource
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
……
//谁能说说这里使用ThreadLocal的好处是什么呢?
Set currentResources = (Set) this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
……
}
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());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
……
}
finally {
……
}
}
2.2.3.3资源定位(resource location)分析
资源定位的定义主要包含两类:单一的资源路径和带有占位符的复合资源路径,其中后一种Spring支持ant-style样式的定义,例如classpath*:/WEF-INF/*-con.xml。无论是哪种类型的资源定位,最后都需要被解释成Resource(资源)。其中第一种由DefaultResourceLoader负责,其实现是通过资源定位尝试构造URL,然后把URL封装成URLResource;后一种由PathMatchingResourcePatternResolver负责,其主要处理ant-style样式的资源定位,其处理的资源主要包括两类:文件系统文件、jar文件(jar、zip、wsjar等),其返回的资源可能包括URLResource、FileSystemResource。
类PathMatchingResourcePatternResolver资源定位:
public Resource getResource(String location) {
return getResourceLoader().getResource(location);
}
/** */ /** ant-style样式定位(包含单独定位),类似与classpath*:/WEF-INF/*-context.xml **/
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
//检查是否以类路径为前缀(classpath*:),例如classpath*:/WEF-INF/*-context.xml
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
//定位模式是否采用了ant-style,即采用*或者?占位符的
if (getPathMatcher().isPattern(
locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))){
// a class path resource pattern
// findPathMatchingResources处理的策略是先获取根路径,然后递归匹配各个子目录下的文件,其处理的文件类型主要有两大类:文件系统文件、jar文件(包括jar、zip、wsjar等)。其返回的Resource主要包括URLResource,FileSystemResource实例.
return findPathMatchingResources(locationPattern);
}
else {
// all class path resources with the given name
// findAllClassPathResources的处理策略主要是通过ClassLoader获得URL,然后构造URLResource
return findAllClassPathResources(locationPattern
.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
// Only look for a pattern after a prefix here
// (to not get fooled by a pattern symbol in a strange prefix).
int prefixEnd = locationPattern.indexOf(":") + 1;
if (getPathMatcher().isPattern(
locationPattern.substring(prefixEnd))) {
// a file pattern
return findPathMatchingResources(locationPattern);
}
else {
// a single resource with the given name
//由DefaultResourceLoader处理,返回UrlResource
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
DefaultResourceLoader资源定位:
Assert.notNull(location, "Location must not be null");
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(
location.substring(CLASSPATH_URL_PREFIX.length())
, getClassLoader());
}
else {
try {
// 其只是尝试把location转化为URL
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
2.2.4 资源的解释以及BeanDefinition的注册
2.2.4.1 doLoadBeanDefinitions方法分析
我们在2.2.3.2节中提到,doLoadBeanDefinitions方法真正进行了资源的加载、解释工作。下面我们看看doLoadBeanDefinitions的实现。
try {
//获取验证模式,如果未配置将采用detected mode
int validationMode = getValidationModeForResource(resource); //Resource被加载为Document
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
//解释resource为BeanDefinition,并注册BeanDefinition
return registerBeanDefinitions(doc, resource);
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
/** *//**这里创建BeanDefinitionDocumentReader接口实例,该实例由DefaultBeanDefinitionDocumentReader担当,其主要依据“spring-beans”DTD和XSD来读取BeanDefinition*/
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
2.2.4.1.1 BeanDefinitionDocumentReader对加载的Document的处理以及Bean注册
spring把解释xml,并发解释的数据转化为BeanDefinition的任务委派给BeanDefinitionDocumentReader,其解释的主要代码如下:
this.readerContext = readerContext;
Element root = doc.getDocumentElement();
//由BeanDefinitionParserDelegate协助完成xml到BeanDefinition的解释工作
BeanDefinitionParserDelegate delegate =
createHelper(readerContext, root);
preProcessXml(root);//空函数实现
//把Element解释为BeanDefinition,并注册
parseBeanDefinitions(root, delegate);
postProcessXml(root);//空函数
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//判断节点是否属于命名空间http://www.springframework.org/schema/beans
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
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;
String namespaceUri = ele.getNamespaceURI();
if (delegate.isDefaultNamespace(namespaceUri)) {
//对xml document的解释工作在这里完成
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
//解释定制元素,例如aop、context等。
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//解释import标签
if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//这里是真正的开始解释bean节点
else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
/** *//**把Element解释成GenericBeanDefinition(BeanDefinition的具体实现),并创建新的BeanDefinitionHolder,并把解释的definition、beanName、aliases封装进BeanDefinitionHolder*/
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);//实现参看后面的parseBeanDefinitionElement方法分析
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//对定制的一些配置进行装饰性解释,例如aop
try {
//注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
……
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinition的注册过程,主要是把解释出来的BeanDefinition、bean名称缓存到内部容器中的过程,并且维护BeanDefinition的一致性。BeanDefination注册的关键代码如下:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//注册BeanDefinition
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//注册bean的别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (int i = 0; i < aliases.length; i++) {
registry.registerAlias(beanName, aliases[i]);
}
}
}
public class DefaultListableBeanFactory
extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
/** *//**Whether to allow re-registration of a different definition with the same name */
private boolean allowBeanDefinitionOverriding = true;
/** *//** Whether to allow eager class loading even for lazy-init beans */
private boolean allowEagerClassLoading = true;
/** *//** Whether bean definition metadata may be cached for all beans */
private boolean configurationFrozen = false;
/** *//** Map of bean definition objects, keyed by bean name *///以ConcurrentMap存储BeanDefinition
private final Map beanDefinitionMap =
CollectionFactory.createConcurrentMapIfPossible(16);
/** *//** List of bean definition names, in registration order *///存储注册的beanName
private final List beanDefinitionNames = new ArrayList();
/** *//** Cached array of bean definition names in case of frozen configuration *///存储被冻结的beanName
private String[] frozenBeanDefinitionNames;
public void registerBeanDefinition(String beanName,
BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
……
}
}
synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//如果相同名字的BeanDefinition已经存在,且不允许覆盖,抛出异常。
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;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
resetBeanDefinition(beanName);
}
}
protected void resetBeanDefinition(String beanName) {
// Remove the merged bean definition for the given bean, if already created.
clearMergedBeanDefinition(beanName);
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
synchronized (getSingletonMutex()) {//
destroySingleton(beanName);
}
// Reset all bean definitions that have the given bean as parent
// (recursively).
for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
String bdName = (String) it.next();
if (!beanName.equals(bdName)) {
BeanDefinition bd = (BeanDefinition) this.beanDefinitionMap.get(bdName);
if (beanName.equals(bd.getParentName())) {
resetBeanDefinition(bdName);
}
}
}
}
spring中bean标签的解释代码一览:
parseBeanDefinitionElement方法分析
该方法主要针对bean标签进行解释处理,解释后的信息封装到GenericBeanDefinition中,然后把beanName、alias、GenericBeanDefinition封装到BeanDefinitionHolder中.
String id = ele.getAttribute(ID_ATTRIBUTE);//取得id属性
//取得name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List aliases = new ArrayList();//aliase属性 例如<alias name="fromName" alias="toName"/>
if (StringUtils.hasLength(nameAttr)) {
//如果name属性存在,则把name的值分解,存储到aliases集合中
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;//默认id的值作为beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {//如果id不存在,且aliases不为空,那么以aliases中的第一个作为beanName
beanName = (String) aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
/*检查在一个文件中,beanName或者alias是否有重复的,如果有重复的报告错误,无重复,则把当前的beanName与alias记录到Set中*/
checkNameUniqueness(beanName, aliases, ele);
}
//对bean的详细解释,主要包括常见的class、parent、lazy-init、singleton等属性
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,其规则如下:
如果beanDefinition存在className,则以"className#编号"或者"className"作为beanName;
如果beanDefinition不存在className,且beanDefinition存在parentName,则以"parentName$child#编号"或者"parentName$child"作为beanName;
如果beanDefinition不存在className,且beanDefinition存在factorybeanName,则以"factoryBeanName$created#编号"或者"factoryBeanName$created"作为beanName;
注意,编号是通过查询容器是否包含beanName,然后累加获得的*/
beanName = this.readerContext.generateBeanName(beanDefinition);
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);
//最后封装为BeanDefinitionHoler返回
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
String className = null;//解释class属性
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {//parent属性
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
try {
//以bean的id作为参数封装到BeanEntry中;ParseState以Stack作为存储数据结构来存储Bean的解释状态
this.parseState.push(new BeanEntry(beanName));
//创建了GenericBeanDefinition,并为其设置parent=='parent',beanClass=='class',beanClassName属性
AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(
parent, className, this.readerContext.getBeanClassLoader());
if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {//解释scope
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Specify either 'scope' or 'singleton', not both", ele);
}
}
else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {//singleton
bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?
BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);
}
else if (containingBean != null) {
bd.setScope(containingBean.getScope());
}
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {//解释abstract
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);//解释lazy-init
if (DEFAULT_VALUE.equals(lazyInit) && bd.isSingleton()) {
// Just apply default to singletons, as lazy-init has no meaning for prototypes.
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);//解释自动装配模式
bd.setAutowireMode(getAutowireMode(autowire));
String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
bd.setDependencyCheck(getDependencyCheck(dependencyCheck));//解释依赖检查
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);//解释depends-on
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, BEAN_NAME_DELIMITERS));
}
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
if (!"".equals(initMethodName)) {
bd.setInitMethodName(initMethodName);
}
}
else {
if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
}
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
if (!"".equals(destroyMethodName)) {
bd.setDestroyMethodName(destroyMethodName);
}
}
else {
if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
}
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {//解释工厂方法属性
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {//解释工厂bean属性
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
parseMetaElements(ele, bd);
/**解释lookup-method(方法注入的一种),还记得吗,使用lookup-method能够覆盖bean标签指定的bean的抽象method(该method由method标签指定),主要针对singleton引用一个prototype的情形*/
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解释replace-method(方法注入的一种)
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
/**这里把解释出来的属性值,ref[RuntimeBeanReference]、list[ManagedList]、set[ManagedSet]、map、properties,封装到PropertyValue,
然后把PropertyValue加入到BeanDefinition*/
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
到此为止,spring IOC容器启动中的内部容器初始化部分基本分析完成。