本文研究Spring配置文件解析到注册的过程。
我们写个demo来进行debug
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("iocbeans.xml"));
复制代码
第一步获取XML的resource。
第二步才是资源的加载。
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, (BeanFactory)null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader = new XmlBeanDefinitionReader(this);
//这里才是资源加载的真正实现
this.reader.loadBeanDefinitions(resource);
}
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return this.loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//...省略部分代码
//通过属性记录当前已经加载的资源
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if(currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if(!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
//获取inputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if(encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//核心逻辑部分
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {//关闭流
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if(((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
复制代码
总结下上面代码的逻辑:
首先对传入的resource参数作封装,原因是可能存在编码的情况。然后准备inputSource对象,方便后面的读取。最后传入doLoadBeanDefinitions方法。
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
//1.加载xml文件,转化为doc格式
Document doc = this.doLoadDocument(inputSource, resource);
//2.根据返回的doc,注册bean信息
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var4) {
throw var4;
}
复制代码
上面1中,会涉及对XML的验证,此处略过。
解析及注册BeanDefinitions
通过上面1,我们已经拿到了Document.开始进入registerBeanDefinitions(doc, resource);
public int registerBeanDefinitions(Document doc, Resource resource) {
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
//记录统计前的bean个数
int countBefore = this.getRegistry().getBeanDefinitionCount();
//加载及注册bean
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
//记录本次加载bean的个数
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
复制代码
其中的参数doc是通过上一节loadDocument加载转换出来的。在这个方法中很好地应用了面向对象中单一职责的原则,将逻辑处理委托给单一的类进行处理,而这个逻辑处理类就是BeanDefinitionDocumentReader。BeanDefinitionDocumentReader是一个接口,而实例化的工作是在createBeanDefinitionDocumentReader()中完成的,而通过此方法BeanDefinitionDocumentReader真正的类型是DefaultBeanDefinitionDocumentReader了,进入后,发现这个方法的重要目的之一就是提取root,以便于再次将root作为参数继续BeanDefiniton的注册。
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
this.logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
this.doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
//专门处理解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if(this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute("profile");
if(StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
//protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if(this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute("profile");
if(StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
// 解析前处理,留给子类实现
this.preProcessXml(root);
this.parseBeanDefinitions(root, this.delegate);
//解析后处理,子类实现
this.postProcessXml(root);
this.delegate = parent;
}
}
复制代码
进入 this.preProcessXml(root)和this.postProcessXml(root)方法会发现它们是空方法。既然是空方法那有什么用呢?我们可以快速反映出这是模版的设计模式。一个类要么是面向继承设计的,要么就用final修饰。这两个方法就是为子类设计的。
下面就开始进行XML的读取了。
void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//对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;
if(delegate.isDefaultNamespace(ele)) {
//对bean的处理
this.parseDefaultElement(ele, delegate);
} else {
//对bean的处理
delegate.parseCustomElement(ele);
}
}
}
} else {
delegate.parseCustomElement(root);
}
}
复制代码
默认标签的解析
默认标签的解析是在parseDefaultElement函数中处理的,函数中的功能一目了然。分别对4种不同的标签作不同的处理。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
复制代码
bean标签的解析及注册
在上面的4种标签解析中,bean标签的解析最重要也最为复杂,我们搞懂她的处理方式,其他的标签解析就会迎刃而解。我们进入代码看下
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//1.委托该方法进行元素解析。经过该方法,bdHolder中拥有配置文件的各种属性了。(class,name,id,alias)
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {//对解析后的bdHolder进行注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
//发出响应事件,通知相关的监听器,这个bean已经加载完成了
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
复制代码
解析BeanDefinition
首先我们从元素解析及信息提取开始, BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele),进入BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法。
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute("id");//对id解析
String nameAttr = ele.getAttribute("name");//对name解析
List<String> aliases = new ArrayList();
if(StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
beanName = (String)aliases.remove(0);
}
if(containingBean == null) {
this.checkNameUniqueness(beanName, aliases, ele);
}
// 对标签其他属性的解析
AbstractBeanDefinition beanDefinition = this.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);
String beanClassName = beanDefinition.getBeanClassName();
if(beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
} catch (Exception var9) {
this.error(var9.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} else {
return null;
}
}
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
String className = null;
//解析class属性
if(ele.hasAttribute("class")) {
className = ele.getAttribute("class").trim();
}
try {//解析parent属性
String parent = null;
if(ele.hasAttribute("parent")) {
parent = ele.getAttribute("parent");
}
//创建用于承载属性的GenericBeanDefinition
AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
//硬编码解析默认bean的各种属性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
//提取description
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
//解析元数据
this.parseMetaElements(ele, bd);
//解析lookup-method
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replaced-method
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数
this.parseConstructorArgElements(ele, bd);
//解析proterty子元素
this.parsePropertyElements(ele, bd);
//解析qualifier子元素
this.parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(this.extractSource(ele));
AbstractBeanDefinition var7 = bd;
return var7;
} catch (ClassNotFoundException var13) {
} finally {
this.parseState.pop();
}
return null;
}
复制代码
终于,bean标签的所有属性,我们都看到了怎么解析的了。
-
创建用于属性承载的BeanDefinition BeanDefiniton是一个接口,在Spring中存在三种实现:RootBeanDefiniton、ChildBeanDefinitio以及GenericBeanDefinition。三种实现均继承AbstractBeanDefinition,其中BeanDefiniton是配置文件元素标签在容器中的表示。它们一一对应。其中RootBeanDefinition是最常用的实现类,它对应一般性的元素标签,GenericBeanDefinition是新加入的bean文件配置属性定义类,是一站式服务类。在配置文件中可以定义父和子,父用RootBeanDefiniton表示,而子用childBeanDefinition表示,而没有父的就使用RootBeanDefiniton表示。Spring通过BeanDefinition将配置文件的信息转化为容器的内部表示,并将这些BeanDefinition注册到BeanDefinitionRegistry中。BeanDefinitionRegistry就是spring的内存数据库,主要以map形式保存,后续直接在BeanDefinitionRegistry获取配置信息。 由此可知,要解析属性首先要创建用于承载属性的实例子,也就是创建GenericBeanDefinition类型的实例。而createBeanDefinition(className, parent)的作用就是实现此功能。 public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if(className != null) { if(classLoader != null) { //如果classLoader不为null,则加载类对象.否则只是记录className bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } }
return bd; } 复制代码
解析各种属性 当我们创建了bean信息的承载实例后,就可以进行bean信息的各种属性解析了。parseBeanDefinitionAttributes是对element所有元素属性进行解析: public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { //解析scope属性 if(ele.hasAttribute("singleton")) { this.error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } else if(ele.hasAttribute("scope")) { bd.setScope(ele.getAttribute("scope")); } else if(containingBean != null) { bd.setScope(containingBean.getScope()); } //解析abstract属性 if(ele.hasAttribute("abstract")) { bd.setAbstract("true".equals(ele.getAttribute("abstract"))); } //解析lazy-init属性 String lazyInit = ele.getAttribute("lazy-init"); if("default".equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); }
bd.setLazyInit("true".equals(lazyInit)); //解析autowire属性 String autowire = ele.getAttribute("autowire"); bd.setAutowireMode(this.getAutowireMode(autowire)); //解析dependency-check属性 String dependencyCheck = ele.getAttribute("dependency-check"); bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck)); String autowireCandidate; //解析depends-on属性 if(ele.hasAttribute("depends-on")) { autowireCandidate = ele.getAttribute("depends-on"); bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; ")); } //解析autowire-candidate属性 autowireCandidate = ele.getAttribute("autowire-candidate"); String destroyMethodName; if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) { bd.setAutowireCandidate("true".equals(autowireCandidate)); } else { destroyMethodName = this.defaults.getAutowireCandidates(); if(destroyMethodName != null) { String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName); bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); } } //解析primary属性 if(ele.hasAttribute("primary")) { bd.setPrimary("true".equals(ele.getAttribute("primary"))); } //解析init-method属性 if(ele.hasAttribute("init-method")) { destroyMethodName = ele.getAttribute("init-method"); if(!"".equals(destroyMethodName)) { bd.setInitMethodName(destroyMethodName); } } else if(this.defaults.getInitMethod() != null) { bd.setInitMethodName(this.defaults.getInitMethod()); bd.setEnforceInitMethod(false); } //解析destroy-method属性 if(ele.hasAttribute("destroy-method")) { destroyMethodName = ele.getAttribute("destroy-method"); bd.setDestroyMethodName(destroyMethodName); } else if(this.defaults.getDestroyMethod() != null) { bd.setDestroyMethodName(this.defaults.getDestroyMethod()); bd.setEnforceDestroyMethod(false); } //解析factory-method属性 if(ele.hasAttribute("factory-method")) { bd.setFactoryMethodName(ele.getAttribute("factory-method")); } //解析factory-bean属性 if(ele.hasAttribute("factory-bean")) { bd.setFactoryBeanName(ele.getAttribute("factory-bean")); } return bd; } 复制代码
经过上面的处理,Spring完成了对所有bean属性的解析。也就是说,XML中所有配置都可以在GenericBeanDefinition的实例类中找到对应的配置。GenericBeanDefinition只是子类实现,而大部分通用的属性都保存在AbstractBeanDefinition中。我们看下这个类
//...省略静态变量以及final常量
private volatile Object beanClass;
private String scope;
private boolean abstractFlag;
private boolean lazyInit;
private int autowireMode;
private int dependencyCheck;
private String[] dependsOn;
private boolean autowireCandidate;
private boolean primary;
private final Map<String, AutowireCandidateQualifier> qualifiers;
private boolean nonPublicAccessAllowed;
private boolean lenientConstructorResolution;
private ConstructorArgumentValues constructorArgumentValues;
private MutablePropertyValues propertyValues;
private MethodOverrides methodOverrides;
private String factoryBeanName;
private String factoryMethodName;
private String initMethodName;
private String destroyMethodName;
private boolean enforceInitMethod;
private boolean enforceDestroyMethod;
private boolean synthetic;
private int role;
private String description;
private Resource resource;
复制代码
注册解析的BeanDefinition
我们解析完配置文件,对于得到的beanDefinition已经可以满足后续使用了,唯一剩下的工作就是注册了。我们进入到
#DefaultBeanDefinitionDocumentReader
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
//使用beanName做唯一标识注册
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//注册所有别名
String[] aliases = definitionHolder.getAliases();
if(aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
复制代码
从上面代码可以看出,解析的beanDefinition都会被注册到BeanDefinitioinRegistry类型的registry中,而对于beanDefinition的注册分成了两部分:beanName注册和别名的注册.
-
通过beanName注册BeanDefinition 对于beanDefinition的注册,本质就是beanName作为key,放入map。 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
if(beanDefinition instanceof AbstractBeanDefinition) { try {//最后一次校验 ((AbstractBeanDefinition)beanDefinition).validate(); } catch (BeanDefinitionValidationException var9) } } BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName); if(oldBeanDefinition != null) { //...省略 如果beanName 存在,且不允许覆盖,就抛出异常 if(!this.isAllowBeanDefinitionOverriding()) { } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if(this.hasBeanCreationStarted()) { Map var4 = this.beanDefinitionMap; //加锁 放进map 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; if(this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if(oldBeanDefinition != null || this.containsSingleton(beanName)) { this.resetBeanDefinition(beanName);//重置所有beanName缓存 } } 复制代码
-
通过别名注册BeanDefinition public void registerAlias(String name, String alias) { //如果beanName与alias相同的话 不记录alias,并删除对应的alias if(alias.equals(name)) { this.aliasMap.remove(alias); } else { String registeredName = (String)this.aliasMap.get(alias); if(registeredName != null) { if(registeredName.equals(name)) { return; }
if(!this.allowAliasOverriding()) { } this.checkForAliasCircle(name, alias); //注册 this.aliasMap.put(alias, name); } } 复制代码
-