本文研究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); } } 复制代码