spring解析配置文件(三)
一、從XmlBeanDefinitionReader的registerBeanDefinitions(doc,resource)開始
1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) 2 throws BeanDefinitionStoreException { 3 try { 4 Document doc = doLoadDocument(inputSource, resource); 5 return registerBeanDefinitions(doc, resource); 6 }進入第5行的registerBeanDefinitions方法
1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { 2 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); 3 int countBefore = getRegistry().getBeanDefinitionCount(); 4 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 5 return getRegistry().getBeanDefinitionCount() - countBefore; 6 }第二行創建了一個bean定義文檔閱讀器,創建的代碼如下,第三行的getRegistry()方法得到是DefaultListableBeanFactory類的實例,是個bean工廠,這個工廠在準備讀取xml時創建xml閱讀器的時候就已經設置進去,getBeanDefinitions方法里的代碼就這一句this.beanDefinitionMap.size(),獲取bean定義容器的大小,很顯然對于我這里是沒有的,因為還沒解析xml。
1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { 2 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); 3 }在看看第4行的documentReader.registerBeanDefinitions這個方法
1 @Override 2 public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { 3 this.readerContext = readerContext; 4 logger.debug("Loading bean definitions"); 5 Element root = doc.getDocumentElement(); 6 doRegisterBeanDefinitions(root); 7 }第5行獲得了xml的根元素<beans>然后調用
doRegisterBeanDefinitions方法,并把根元素傳入進入1 protected void doRegisterBeanDefinitions(Element root) { 2 // Any nested <beans> elements will cause recursion in this method. In 3 // order to propagate and preserve <beans> default-* attributes correctly, 4 // keep track of the current (parent) delegate, which may be null. Create 5 // the new (child) delegate with a reference to the parent for fallback purposes, 6 // then ultimately reset this.delegate back to its original (parent) reference. 7 // this behavior emulates a stack of delegates without actually necessitating one. 8 BeanDefinitionParserDelegate parent = this.delegate; 9 this.delegate = createDelegate(getReaderContext(), root, parent); 10 11 if (this.delegate.isDefaultNamespace(root)) { 12 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); 13 if (StringUtils.hasText(profileSpec)) { 14 String[] specifiedProfiles = StringUtils.tokenizeToStringArray( 15 profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); 16 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { 17 return; 18 } 19 } 20 } 21 22 preProcessXml(root); 23 parseBeanDefinitions(root, this.delegate); 24 postProcessXml(root); 25 26 this.delegate = parent; 27 } 第9行創建了使用createDelegate方法創建了一個BeanDefinitionParserDelegate類的實例,它內部的代碼如下 1 protected BeanDefinitionParserDelegate createDelegate( 2 XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { 3 4 BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); 5 delegate.initDefaults(root, parentDelegate); 6 return delegate; 7 }
第4行的readerContext是一個XMLReaderContext,繼續往下調用了initDefaults方法,初始化默認值
1 public void initDefaults(Element root, BeanDefinitionParserDelegate parent) { 2 populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root); 3 this.readerContext.fireDefaultsRegistered(this.defaults); 4 }進入populateDefaults方法
1 protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) { 2 String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE); 3 if (DEFAULT_VALUE.equals(lazyInit)) { 4 // Potentially inherited from outer <beans> sections, otherwise falling back to false. 5 lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE); 6 } 7 defaults.setLazyInit(lazyInit); 8 9 String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE); 10 if (DEFAULT_VALUE.equals(merge)) { 11 // Potentially inherited from outer <beans> sections, otherwise falling back to false. 12 merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE); 13 } 14 defaults.setMerge(merge); 15 16 String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE); 17 if (DEFAULT_VALUE.equals(autowire)) { 18 // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'. 19 autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE); 20 } 21 defaults.setAutowire(autowire); 22 23 // Don't fall back to parentDefaults for dependency-check as it's no longer supported in 24 // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it. 25 defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE)); 26 27 if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) { 28 defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)); 29 } 30 else if (parentDefaults != null) { 31 defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates()); 32 } 33 34 if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) { 35 defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)); 36 } 37 else if (parentDefaults != null) { 38 defaults.setInitMethod(parentDefaults.getInitMethod()); 39 } 40 41 if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) { 42 defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)); 43 } 44 else if (parentDefaults != null) { 45 defaults.setDestroyMethod(parentDefaults.getDestroyMethod()); 46 } 47 48 defaults.setSource(this.readerContext.extractSource(root)); 49 }第2行的DEFAULT_LAZY_INIT_ATTRIBUTE的值是default-lazy-init,第7行設置懶加載,還有默認的初始化方法什么的,把這些個屬性全都設置到
DocumentDefaultsDefinition 中。這個方法返回后繼續調用了XmlReaderContext的fireDefaultsRegistered方法,不過里面啥都沒做。接下來有回到了doRegisterBeanDefinitions方法 1 protected void doRegisterBeanDefinitions(Element root) { 2 // Any nested <beans> elements will cause recursion in this method. In 3 // order to propagate and preserve <beans> default-* attributes correctly, 4 // keep track of the current (parent) delegate, which may be null. Create 5 // the new (child) delegate with a reference to the parent for fallback purposes, 6 // then ultimately reset this.delegate back to its original (parent) reference. 7 // this behavior emulates a stack of delegates without actually necessitating one. 8 BeanDefinitionParserDelegate parent = this.delegate; 9 this.delegate = createDelegate(getReaderContext(), root, parent); 10 11 if (this.delegate.isDefaultNamespace(root)) { 12 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); 13 if (StringUtils.hasText(profileSpec)) { 14 String[] specifiedProfiles = StringUtils.tokenizeToStringArray( 15 profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); 16 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { 17 return; 18 } 19 } 20 } 21 22 preProcessXml(root); 23 parseBeanDefinitions(root, this.delegate); 24 postProcessXml(root); 25 26 this.delegate = parent; 27 }
第11行判斷當前的根元素是否是默認的命名空間,spring中存在著兩種標簽,一種是默認的標簽,另一種是自定義標簽
第12行獲得profile屬性,這個屬性應用于對個beans標簽的情況,從spring3開始的,這樣我們可以寫多套bean定義,特別是使用到數據源的時候,可以切換不同的數據源,想要使用哪個bean定義就激活誰,想詳細了解的,可以去查查資料。
第22行是個空方法,里面什么也沒做,這個地方可以進行擴展,在解析bean定義之前,可以先處理自定義的標簽
第23行方法的代碼如下
1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { 2 if (delegate.isDefaultNamespace(root)) { 3 NodeList nl = root.getChildNodes(); 4 for (int i = 0; i < nl.getLength(); i++) { 5 Node node = nl.item(i); 6 if (node instanceof Element) { 7 Element ele = (Element) node; 8 if (delegate.isDefaultNamespace(ele)) { 9 parseDefaultElement(ele, delegate); 10 } 11 else { 12 delegate.parseCustomElement(ele); 13 } 14 } 15 } 16 } 17 else { 18 delegate.parseCustomElement(root); 19 } 20 }第2行判斷root是否是默認的命名空間,第3行獲得根元素下的子節點,循環遍歷子節點,第8行判斷每個子節點是否是默認的命名空間,如果是就執行parseDefaultElement方法,否則
執行parseCustomElement方法,什么是自定義的標簽呢,比如用戶自己實現的標簽,還有就是spring的aop,tx這類標簽都是有自定義的命名空間的標簽
我們進到parseCustomElement方法中看看
1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { 2 String namespaceUri = getNamespaceURI(ele); 3 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 4 if (handler == null) { 5 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); 6 return null; 7 } 8 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); 9 }第2行獲取這個元素的命名空間,通過命名空間可以在類路徑下的spring.handlers中找到對應的處理器,在spring.schemas中找到對應的xsd文件。進入resolve方法查看一下他的
代碼邏輯
1 @Override 2 public NamespaceHandler resolve(String namespaceUri) { 3 Map<String, Object> handlerMappings = getHandlerMappings(); 4 Object handlerOrClassName = handlerMappings.get(namespaceUri); 5 if (handlerOrClassName == null) { 6 return null; 7 } 8 else if (handlerOrClassName instanceof NamespaceHandler) { 9 return (NamespaceHandler) handlerOrClassName; 10 } 11 else { 12 String className = (String) handlerOrClassName; 13 try { 14 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); 15 if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { 16 throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + 17 "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); 18 } 19 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); 20 namespaceHandler.init(); 21 handlerMappings.put(namespaceUri, namespaceHandler); 22 return namespaceHandler; 23 } 24 catch (ClassNotFoundException ex) { 25 throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + 26 namespaceUri + "] not found", ex); 27 } 28 catch (LinkageError err) { 29 throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + 30 namespaceUri + "]: problem with handler class file or dependent class", err); 31 } 32 } 33 }第3行代碼getHandlerMappings()獲得所有的命名空間和處理程序的映射
1 private Map<String, Object> getHandlerMappings() { 2 if (this.handlerMappings == null) { 3 synchronized (this) { 4 if (this.handlerMappings == null) { 5 try { 6 Properties mappings = 7 PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); 8 if (logger.isDebugEnabled()) { 9 logger.debug("Loaded NamespaceHandler mappings: " + mappings); 10 } 11 Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size()); 12 CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); 13 this.handlerMappings = handlerMappings; 14 } 15 catch (IOException ex) { 16 throw new IllegalStateException( 17 "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex); 18 } 19 } 20 } 21 } 22 return this.handlerMappings; 23 }進入第7行看看
1 public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException { 2 Assert.notNull(resourceName, "Resource name must not be null"); 3 ClassLoader classLoaderToUse = classLoader; 4 if (classLoaderToUse == null) { 5 classLoaderToUse = ClassUtils.getDefaultClassLoader(); 6 } 7 Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) : 8 ClassLoader.getSystemResources(resourceName)); 9 Properties props = new Properties(); 10 while (urls.hasMoreElements()) { 11 URL url = urls.nextElement(); 12 URLConnection con = url.openConnection(); 13 ResourceUtils.useCachesIfNecessary(con); 14 InputStream is = con.getInputStream(); 15 try { 16 if (resourceName.endsWith(XML_FILE_EXTENSION)) { 17 props.loadFromXML(is); 18 } 19 else { 20 props.load(is); 21 } 22 } 23 finally { 24 is.close(); 25 } 26 } 27 return props; 28 }它是通過加載器加載classpath下的META-INF/spring.handler文件,使用jdk的Properties方法加載,加載完后返回properties的實例,最后拿到對應的標簽處理器
?
?拿到命名空間處理器的類名后
1 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); 2 namespaceHandler.init(); 3 handlerMappings.put(namespaceUri, namespaceHandler); 4 return namespaceHandler;第1行使用bean助手類實例化了這個命名空間處理器,并進行了初始化,加入我顯示使用的是aop的命名空間,那么這個命名空間處理器是AopNamespaceHandler類的實例
它對應init方法代碼如下:這個aop命名空間處理器中擁有下面這些類別的標簽解析器,第一個我們是最屬性的,這個解析器里提供了aop:config標簽中pointcut,before之類的解析方法
第3行將初始化好的命名空間處理器放到handlerMappings中,如果下次要使用就直接可以拿到,不需要在此實例化
@Overridepublic void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace as of 2.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}下面是一些bean定義解析器的繼承結構,各種各樣的解析器
?
向處理器中注冊解析器1 protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { 2 this.parsers.put(elementName, parser); 3 }
第2行的parsers是一個Map,用來存放bean定義解析器
得到命名空間處理器后再調用命名空間處理器的parse方法handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));進入parse方法,這個方法又調用了findParserForElement方法
1 private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
2 String localName = parserContext.getDelegate().getLocalName(element); 3 BeanDefinitionParser parser = this.parsers.get(localName); 4 if (parser == null) { 5 parserContext.getReaderContext().fatal( 6 "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); 7 } 8 return parser; 9 }
第2行,通過這個元素拿到了它的本地名字,比如aop:config元素的本地名為config
通過config從命名空間中的解析器map容器中拿到了對應的解析器,然后調用這個aop的config解析器的parse方法
1 @Override 2 public BeanDefinition parse(Element element, ParserContext parserContext) { 3 CompositeComponentDefinition compositeDef =4 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); 5 parserContext.pushContainingComponent(compositeDef); 6 7 configureAutoProxyCreator(parserContext, element); 8 9 List<Element> childElts = DomUtils.getChildElements(element); 10 for (Element elt: childElts) { 11 String localName = parserContext.getDelegate().getLocalName(elt); 12 if (POINTCUT.equals(localName)) { 13 parsePointcut(elt, parserContext); 14 } 15 else if (ADVISOR.equals(localName)) { 16 parseAdvisor(elt, parserContext); 17 } 18 else if (ASPECT.equals(localName)) { 19 parseAspect(elt, parserContext); 20 } 21 } 22 23 parserContext.popAndRegisterContainingComponent(); 24 return null; 25 }?
第三行創建了一個組件定義,并將它壓入ParseContext上下文中的stack中進入第7行的方法
1 private void configureAutoProxyCreator(ParserContext parserContext, Element element) { 2 AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element); 3 }
這個方法是在配置自動代理創建者,這個方法在配置了<aop:config>才使用,如果你配置的是<aop:aspect-autoproxy/>這個標簽,就會使用AspectJAutoProxyBeanDefinitionParser這個類的解析器?;氐絘op:config這個標簽的解析器,上面的第2行使用了AopNamespaceUtils aop命名空間助手類注冊一個自動代理切面創建者,進入這個方法看看
1 public static void registerAspectJAutoProxyCreatorIfNecessary( 2 ParserContext parserContext, Element sourceElement) { 3 4 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( 5 parserContext.getRegistry(), parserContext.extractSource(sourceElement)); 6 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); 7 registerComponentIfNecessary(beanDefinition, parserContext); 8 }?
第4行調用了registerAspectJAutoProxyCreatorIfNecessary的重載方法,這個方法傳入了BeanRegistry類的對象(這里的這個實例實際上是DefaultListableBeanFactory)和ParseContext包裝后的可提取資源實例進入這個方法查看一下它的代碼 1 public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { 2 return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source); 3 }
第2行傳入了一個AspectJAwareAdvisorAutoProxyCreator.class類對象,暫且不管它是干啥的,繼續往下看
1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { 2 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 3 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 4 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 5 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { 6 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); 7 int requiredPriority = findPriorityForClass(cls); 8 if (currentPriority < requiredPriority) { 9 apcDefinition.setBeanClassName(cls.getName()); 10 } 11 } 12 return null; 13 } 14 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); 15 beanDefinition.setSource(source); 16 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); 17 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 18 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); 19 return beanDefinition; 20 }第3行判斷這個BeanFactory中的BeanDefinitionMap容器中是否存在一個key叫做AUTO_PROXY_CREATOR_BEAN_NAME
(org.springframework.aop.config.internalAutoProxyCreator)的元素,如果存在就獲得他的BeanDefinition對象,并且與我們傳進來的AspectJAwareAdvisorAutoProxyCreator
類名是否一樣,如果一樣就要根據優先級來選擇其中一個作為自動創建代理類,在AopConfigUtils類中有個靜態的屬性list集合APC_PRIORITY_LIST,
它在靜態塊中初始化
1 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>(); 2 3 /** 4 * Setup the escalation list. 5 */ 6 static { 7 APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); 8 APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); 9 APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); 10 }我們在看看findPriorityForClass()方法
private static int findPriorityForClass(String className) {for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {Class<?> clazz = APC_PRIORITY_LIST.get(i);if (clazz.getName().equals(className)) {return i;}}throw new IllegalArgumentException("Class name [" + className + "] is not a known auto-proxy creator class");}}看見了,它是以這些定義的順序進行決定優先級的,只不過在集合中越后,優先級就越高
讓我們再次返回到registerOrEscalateApcAsRequired這個方法
1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) { 2 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 3 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 4 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 5 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { 6 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); 7 int requiredPriority = findPriorityForClass(cls); 8 if (currentPriority < requiredPriority) { 9 apcDefinition.setBeanClassName(cls.getName()); 10 } 11 } 12 return null; 13 } 14 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); 15 beanDefinition.setSource(source); 16 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); 17 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); 18 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); 19 return beanDefinition; 20 }如果容器中沒有AUTO_PROXY_CREATOR_BEAN_NAME對應的自動代理器,那么就跳到第14行,創建一個AspectJAwareAdvisorAutoProxyCreator實例注入到RootBeanDefinition類中,這個類是BeanDefinition的子類,第16行設置了這個BeanDefinition的優先級,第17行設置這個BeanDefinition的角色定位,用戶自己定義的bean的角色是BeanDefinition.ROLE_APPLICTION
?第18行向beanFactory中注冊這個BeanDefinition,它的實現代碼如下
1 @Override 2 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 3 throws BeanDefinitionStoreException { 4 5 Assert.hasText(beanName, "Bean name must not be empty"); 6 Assert.notNull(beanDefinition, "BeanDefinition must not be null"); 7 8 if (beanDefinition instanceof AbstractBeanDefinition) { 9 try { 10 ((AbstractBeanDefinition) beanDefinition).validate(); 11 } 12 catch (BeanDefinitionValidationException ex) { 13 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 14 "Validation of bean definition failed", ex); 15 } 16 } 17 18 BeanDefinition oldBeanDefinition; 19 20 oldBeanDefinition = this.beanDefinitionMap.get(beanName); 21 if (oldBeanDefinition != null) { 22 if (!isAllowBeanDefinitionOverriding()) { 23 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 24 "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + 25 "': There is already [" + oldBeanDefinition + "] bound."); 26 } 27 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { 28 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE 29 if (this.logger.isWarnEnabled()) { 30 this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + 31 "' with a framework-generated bean definition: replacing [" + 32 oldBeanDefinition + "] with [" + beanDefinition + "]"); 33 } 34 } 35 else if (!beanDefinition.equals(oldBeanDefinition)) { 36 if (this.logger.isInfoEnabled()) { 37 this.logger.info("Overriding bean definition for bean '" + beanName + 38 "' with a different definition: replacing [" + oldBeanDefinition + 39 "] with [" + beanDefinition + "]"); 40 } 41 } 42 else { 43 if (this.logger.isDebugEnabled()) { 44 this.logger.debug("Overriding bean definition for bean '" + beanName + 45 "' with an equivalent definition: replacing [" + oldBeanDefinition + 46 "] with [" + beanDefinition + "]"); 47 } 48 } 49 this.beanDefinitionMap.put(beanName, beanDefinition); 50 } 51 else { 52 if (hasBeanCreationStarted()) { 53 // Cannot modify startup-time collection elements anymore (for stable iteration) 54 synchronized (this.beanDefinitionMap) { 55 this.beanDefinitionMap.put(beanName, beanDefinition); 56 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); 57 updatedDefinitions.addAll(this.beanDefinitionNames); 58 updatedDefinitions.add(beanName); 59 this.beanDefinitionNames = updatedDefinitions; 60 if (this.manualSingletonNames.contains(beanName)) { 61 Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); 62 updatedSingletons.remove(beanName); 63 this.manualSingletonNames = updatedSingletons; 64 } 65 } 66 } 67 else { 68 // Still in startup registration phase 69 this.beanDefinitionMap.put(beanName, beanDefinition); 70 this.beanDefinitionNames.add(beanName); 71 this.manualSingletonNames.remove(beanName); 72 } 73 this.frozenBeanDefinitionNames = null; 74 } 75 76 if (oldBeanDefinition != null || containsSingleton(beanName)) { 77 resetBeanDefinition(beanName); 78 } 79 }第10行對這個BeanDefinition進行驗證,如果這個BeanDefinition有需要重載的方法,并且還存在工廠方法,那就報錯,這兩者不能共存。靜態工廠必須創建bean的實例
什么是重載的方法,比如使用了lookup-method,replace-method這些標簽,比如:
<bean id="service" class="com.test.UserService" scope="prototype" />
<bean?id="userService"?class="com.test.UserServiceCreator">
<lookup-method?name="getService"?bean="server"?/> ?
</bean>
我們調用UserServiceCreator的getService,取出來的值是UseService的實例,如果此時我們把UserSericeCreator設置一個靜態工廠方法,修改成下面這種
<bean?id="userService"?class="com.test.UserServiceCreator" factory-method="createService">
<lookup-method?name="getService"?bean="server"?/> ?
</bean>
這樣配置是錯誤的,在Spring創建bean實例的時候,spring就不知你要創建的是哪個對象了,這個id為userService的bean應該是UserServiceCreator的代理實例(方法重載會用到動態代理)還是工廠方法createService創建的UserService實例,所以只能報錯。
第20行是獲得老的BeanDefinition,如果存在老的BeanDefinition,就檢查是否允許覆蓋
第49行將定義好的BeanDefinition存到BeanFactory的beanDefinitionMap中,覆蓋oldBeanDefinition
如果不存在oldBeanDefinition,那么跳到52行,判斷是不是已經開始開始創建bean了,內部代碼只是判斷bean工廠的屬性alreadyCreated集合是否不為空,為空就表示還沒有開始,不為空表示開始了
第69行將BeanDefinition注冊到容器中,第70行將BeanDefinition的名字注入到容器中
創建好AspectJAwareAdvisorAutoProxyCreator類的BeanDefinition后,繼續調用了AopNamespaceUtils的useClassProxyingIfNecessary方法
1 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) { 2 if (sourceElement != null) { 3 boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); 4 if (proxyTargetClass) { 5 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); 6 } 7 boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); 8 if (exposeProxy) { 9 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); 10 } 11 } 12 }第3行的PROXY_TARGET_CLASS_ATTRIBUTE的值為proxy-target-class,如果這個屬性為true那么就使用cglib做代理,默認為false使用JDK的動態代理
進入第5行的forceAutoProxyCreatorToUseClassProxying方法
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);}很顯然BeanFactory中是存在AUTO_PROXY_CREATOR_BEAN_NAME的,這個key對應對象是AspectJAwareAdvisorAutoProxyCreator的BeanDefinition,前面已經說過了。
如果存在就給這個BeanDefinition添加屬性值proxyTargetClass為true,表示將使用cglib進行代理,后面創建代理類的時候會再次提到
第7行判斷當前是否需要暴露代理
useClassProxyingIfNecessary方法調用結束后有調用了AopNamespaceUtils的registerComponentIfNecessary方法
?
1 private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) { 2 if (beanDefinition != null) { 3 BeanComponentDefinition componentDefinition = 4 new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); 5 parserContext.registerComponent(componentDefinition); 6 } 7 }第4行代碼內部調用了以下這個方法,它在尋找propertyValues中是否有嵌入的BeanDefinition,BeanDefinitionHolder
1 private void findInnerBeanDefinitionsAndBeanReferences(BeanDefinition beanDefinition) { 2 List<BeanDefinition> innerBeans = new ArrayList<BeanDefinition>(); 3 List<BeanReference> references = new ArrayList<BeanReference>(); 4 PropertyValues propertyValues = beanDefinition.getPropertyValues(); 5 for (int i = 0; i < propertyValues.getPropertyValues().length; i++) { 6 PropertyValue propertyValue = propertyValues.getPropertyValues()[i]; 7 Object value = propertyValue.getValue(); 8 if (value instanceof BeanDefinitionHolder) { 9 innerBeans.add(((BeanDefinitionHolder) value).getBeanDefinition()); 10 } 11 else if (value instanceof BeanDefinition) { 12 innerBeans.add((BeanDefinition) value); 13 } 14 else if (value instanceof BeanReference) { 15 references.add((BeanReference) value); 16 } 17 } 18 this.innerBeanDefinitions = innerBeans.toArray(new BeanDefinition[innerBeans.size()]); 19 this.beanReferences = references.toArray(new BeanReference[references.size()]); 20 }返回到上一層
1 private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) { 2 if (beanDefinition != null) { 3 BeanComponentDefinition componentDefinition = 4 new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); 5 parserContext.registerComponent(componentDefinition); 6 } 7 }這個BeanComponentDefinition類是BeanDefinitionHolder的子類,從名字可以看出它叫BeanDefinition持有者,內部有一個beanName屬性,相對應就有個BeanDefinition屬性
第5行將這個復合的BeanDefinitionHolder注冊到了ParseContext的一個叫containingComponents的stack中
這些方法調用完成后我們直接返回到ConfigBeanDefinitionParser類的parse方法。之前我們分析的是下面方法的第6行的configureAutoProxyCreator方法,有點繞,自己分析的時候需要結合
序列圖來看源碼
1 public BeanDefinition parse(Element element, ParserContext parserContext) { 2 CompositeComponentDefinition compositeDef = 3 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); 4 parserContext.pushContainingComponent(compositeDef); 5 6 configureAutoProxyCreator(parserContext, element); 7 8 List<Element> childElts = DomUtils.getChildElements(element); 9 for (Element elt: childElts) { 10 String localName = parserContext.getDelegate().getLocalName(elt); 11 if (POINTCUT.equals(localName)) { 12 parsePointcut(elt, parserContext); 13 } 14 else if (ADVISOR.equals(localName)) { 15 parseAdvisor(elt, parserContext); 16 } 17 else if (ASPECT.equals(localName)) { 18 parseAspect(elt, parserContext); 19 } 20 } 21 22 parserContext.popAndRegisterContainingComponent(); 23 return null; 24 }第8行取得了<aop:config>的子元素,我這里就一個子元素<aop:aspect>
循環遍歷子元素,下面是ConfigBeanDefinitionParser類定義的標簽元素
class ConfigBeanDefinitionParser implements BeanDefinitionParser {private static final String ASPECT = "aspect";private static final String EXPRESSION = "expression";private static final String ID = "id";private static final String POINTCUT = "pointcut";private static final String ADVICE_BEAN_NAME = "adviceBeanName";private static final String ADVISOR = "advisor";private static final String ADVICE_REF = "advice-ref";private static final String POINTCUT_REF = "pointcut-ref";private static final String REF = "ref";private static final String BEFORE = "before";private static final String DECLARE_PARENTS = "declare-parents";private static final String TYPE_PATTERN = "types-matching";private static final String DEFAULT_IMPL = "default-impl";private static final String DELEGATE_REF = "delegate-ref";private static final String IMPLEMENT_INTERFACE = "implement-interface";private static final String AFTER = "after";private static final String AFTER_RETURNING_ELEMENT = "after-returning";private static final String AFTER_THROWING_ELEMENT = "after-throwing";private static final String AROUND = "around";private static final String RETURNING = "returning";private static final String RETURNING_PROPERTY = "returningName";private static final String THROWING = "throwing";private static final String THROWING_PROPERTY = "throwingName";private static final String ARG_NAMES = "arg-names";private static final String ARG_NAMES_PROPERTY = "argumentNames";private static final String ASPECT_NAME_PROPERTY = "aspectName";private static final String DECLARATION_ORDER_PROPERTY = "declarationOrder";private static final String ORDER_PROPERTY = "order";private static final int METHOD_INDEX = 0;private static final int POINTCUT_INDEX = 1;private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2;上面這些靜態常量很眼熟吧。我的測試標簽是aop:aspect,所以我們直接跳到第18行,進入到parseAspect方法看看
1 private void parseAspect(Element aspectElement, ParserContext parserContext) { 2 String aspectId = aspectElement.getAttribute(ID); 3 String aspectName = aspectElement.getAttribute(REF); 4 5 try { 6 this.parseState.push(new AspectEntry(aspectId, aspectName)); 7 List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>(); 8 List<BeanReference> beanReferences = new ArrayList<BeanReference>(); 9 10 List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS); 11 for (int i = METHOD_INDEX; i < declareParents.size(); i++) { 12 Element declareParentsElement = declareParents.get(i); 13 beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext)); 14 } 15 16 // We have to parse "advice" and all the advice kinds in one loop, to get the 17 // ordering semantics right. 18 NodeList nodeList = aspectElement.getChildNodes(); 19 boolean adviceFoundAlready = false; 20 for (int i = 0; i < nodeList.getLength(); i++) { 21 Node node = nodeList.item(i); 22 if (isAdviceNode(node, parserContext)) { 23 if (!adviceFoundAlready) { 24 adviceFoundAlready = true; 25 if (!StringUtils.hasText(aspectName)) { 26 parserContext.getReaderContext().error( 27 "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.", 28 aspectElement, this.parseState.snapshot()); 29 return; 30 } 31 beanReferences.add(new RuntimeBeanReference(aspectName)); 32 } 33 AbstractBeanDefinition advisorDefinition = parseAdvice( 34 aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences); 35 beanDefinitions.add(advisorDefinition); 36 } 37 } 38 39 AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition( 40 aspectElement, aspectId, beanDefinitions, beanReferences, parserContext); 41 parserContext.pushContainingComponent(aspectComponentDefinition); 42 43 List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT); 44 for (Element pointcutElement : pointcuts) { 45 parsePointcut(pointcutElement, parserContext); 46 } 47 48 parserContext.popAndRegisterContainingComponent(); 49 } 50 finally { 51 this.parseState.pop(); 52 } 53 }第2,3行獲得ID和bean的引用
第6行將ID和ref包裝成一個entry壓入到一個叫做parseState的stack中
第10行意思是在aspect元素下尋找declare-parents子元素,這個故事告訴我們spring的助手類真的很好用。這個標簽是用于給某個類設置父類。如果對這個標簽感興趣可以去搜索相關的資料
第18行取得了aspect下的所有子元素
第22行判斷當前標簽是不是通知類型的標簽,具體的實現代碼如下
private boolean isAdviceNode(Node aNode, ParserContext parserContext) {if (!(aNode instanceof Element)) {return false;}else {String name = parserContext.getDelegate().getLocalName(aNode);return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));}}當找到通知類型的標簽,如aop:before,我們跳到第33行,看看parseAdvice方法
1 private AbstractBeanDefinition parseAdvice( 2 String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext, 3 List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { 4 5 try { 6 this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement))); 7 8 // create the method factory bean 9 RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class); 10 methodDefinition.getPropertyValues().add("targetBeanName", aspectName); 11 methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method")); 12 methodDefinition.setSynthetic(true); 13 14 // create instance factory definition 15 RootBeanDefinition aspectFactoryDef = 16 new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class); 17 aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName); 18 aspectFactoryDef.setSynthetic(true); 19 20 // register the pointcut 21 AbstractBeanDefinition adviceDef = createAdviceDefinition( 22 adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef, 23 beanDefinitions, beanReferences); 24 25 // configure the advisor 26 RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class); 27 advisorDefinition.setSource(parserContext.extractSource(adviceElement)); 28 advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef); 29 if (aspectElement.hasAttribute(ORDER_PROPERTY)) { 30 advisorDefinition.getPropertyValues().add( 31 ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY)); 32 } 33 34 // register the final advisor 35 parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition); 36 37 return advisorDefinition; 38 } 39 finally { 40 this.parseState.pop(); 41 } 42 }第9行又創建了一個RootBeanDefinition的實例
第10行將切面的id和切面的方法保存到這個RootBeanDefinition中
主要看到第21createAdviceDefinition的代碼
1 private AbstractBeanDefinition createAdviceDefinition( 2 Element adviceElement, ParserContext parserContext, String aspectName, int order, 3 RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef, 4 List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) { 5 6 RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext)); 7 adviceDefinition.setSource(parserContext.extractSource(adviceElement)); 8 //添加切面名 9 adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName); 10 adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order); 11 //判斷是否存在returning屬性 12 if (adviceElement.hasAttribute(RETURNING)) { 13 adviceDefinition.getPropertyValues().add( 14 RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING)); 15 } 16 if (adviceElement.hasAttribute(THROWING)) { 17 adviceDefinition.getPropertyValues().add( 18 THROWING_PROPERTY, adviceElement.getAttribute(THROWING)); 19 }//判斷是否有參數 20 if (adviceElement.hasAttribute(ARG_NAMES)) { 21 adviceDefinition.getPropertyValues().add( 22 ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES)); 23 } 24 25 ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); 26 cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); 27 28 Object pointcut = parsePointcutProperty(adviceElement, parserContext); 29 if (pointcut instanceof BeanDefinition) { 30 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut); 31 beanDefinitions.add((BeanDefinition) pointcut); 32 } 33 else if (pointcut instanceof String) { 34 RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut); 35 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef); 36 beanReferences.add(pointcutRef); 37 } 38 39 cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef); 40 41 return adviceDefinition; 42 }
第28行從這個通知元素中解析切點引用pointcut-ref,如果你在這個通知標簽中使用的pointcut屬性,那么會返回一個BeanDefinition類型
講了這么多BeanDefinition,這個BeanDefinition到底是個什么東西,BeanDefinition翻譯過來就是bean定義的意思,相當于將xml文件中定義的Bean
翻譯成java代碼,如<bean id="hello" class="com.test.Hello" scope="singleton" />在BeanDefinition這個類中會都會有相對應的屬性,它也有id
有className,有scope,有initMethodName,有destroyMethodName這些個屬性,就相當于把xml定義的bean翻譯成java代碼。
通知類型的標簽設置完成后,我們再看看pointcut的解析
1 private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) { 2 String id = pointcutElement.getAttribute(ID); 3 String expression = pointcutElement.getAttribute(EXPRESSION); 4 5 AbstractBeanDefinition pointcutDefinition = null; 6 7 try { 8 this.parseState.push(new PointcutEntry(id)); 9 pointcutDefinition = createPointcutDefinition(expression); 10 pointcutDefinition.setSource(parserContext.extractSource(pointcutElement)); 11 12 String pointcutBeanName = id; 13 if (StringUtils.hasText(pointcutBeanName)) { 14 parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition); 15 } 16 else { 17 pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition); 18 } 19 20 parserContext.registerComponent( 21 new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression)); 22 } 23 finally { 24 this.parseState.pop(); 25 } 26 27 return pointcutDefinition; 28 }?第9行創建了一個屬性className為AspectJExpressionPointcut的BeanDefinition,具體這個拿來干嘛的,到后面使用到的時候再說,一路debug過來,定義了一大堆的BeanDefinition
都是為后面創建bean做準備
第14行把創建的切點BeanDefinition注冊到BeanFactory中
至此可以發現,所謂的xml的解析,都是將相應的配置信息解析出來封裝成一個叫做BeanDefinition的對象,最后注冊到BeanFactory的BeanDefinitionMap的map容器中
aop:config解析完成后,我們看看bean標簽的解析,bean是屬于默認的命名空間中定義的標簽,解析時使用的DefaultBeanDefinitionDocumentReader類的parseDefaultElement方法
1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 2 if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { 3 importBeanDefinitionResource(ele); 4 } 5 else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { 6 processAliasRegistration(ele); 7 } 8 else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { 9 processBeanDefinition(ele, delegate); 10 } 11 else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { 12 // recurse 13 doRegisterBeanDefinitions(ele); 14 } 15 }我們解析的是bean標簽,所以直接跳到第8行,看看processBeanDefinition方法
1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 2 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 3 if (bdHolder != null) { 4 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 5 try { 6 // Register the final decorated instance. 7 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 8 } 9 catch (BeanDefinitionStoreException ex) { 10 getReaderContext().error("Failed to register bean definition with name '" + 11 bdHolder.getBeanName() + "'", ele, ex); 12 } 13 // Send registration event. 14 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 15 } 16 }進入第2行的parseBeanDefinitionElement
1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { 2 String id = ele.getAttribute(ID_ATTRIBUTE);//取得bean標簽的id 3 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//取得Bean標簽的name屬性 4 5 List<String> aliases = new ArrayList<String>(); 6 if (StringUtils.hasLength(nameAttr)) { 7 String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);//將name屬性的到的名字按,分割,并作為別名 8 aliases.addAll(Arrays.asList(nameArr)); 9 } 10 11 String beanName = id; 12 if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { 13 beanName = aliases.remove(0); 14 if (logger.isDebugEnabled()) { 15 logger.debug("No XML 'id' specified - using '" + beanName + 16 "' as bean name and " + aliases + " as aliases"); 17 } 18 } 19 20 if (containingBean == null) { 21 checkNameUniqueness(beanName, aliases, ele); 22 } 23 24 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); 25 if (beanDefinition != null) { 26 if (!StringUtils.hasText(beanName)) { 27 try { 28 if (containingBean != null) { 29 beanName = BeanDefinitionReaderUtils.generateBeanName( 30 beanDefinition, this.readerContext.getRegistry(), true); 31 } 32 else { 33 beanName = this.readerContext.generateBeanName(beanDefinition); 34 // Register an alias for the plain bean class name, if still possible, 35 // if the generator returned the class name plus a suffix. 36 // This is expected for Spring 1.2/2.0 backwards compatibility. 37 String beanClassName = beanDefinition.getBeanClassName(); 38 if (beanClassName != null && 39 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && 40 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { 41 aliases.add(beanClassName); 42 } 43 } 44 if (logger.isDebugEnabled()) { 45 logger.debug("Neither XML 'id' nor 'name' specified - " + 46 "using generated bean name [" + beanName + "]"); 47 } 48 } 49 catch (Exception ex) { 50 error(ex.getMessage(), ele); 51 return null; 52 } 53 } 54 String[] aliasesArray = StringUtils.toStringArray(aliases); 55 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); 56 } 57 58 return null; 59 }第12表示,如果存在id和name,并且id沒有值,name有值,那么就取name的第一個name值做為beanName
第21行,對beanName和別名進行檢查,BeanDefinitionParserDelegate類中有個usedNames容器,這個容器用于保存已經使用了的beanName,所以這個方法是在檢查是否有重復定義的beanName或者別名
第24行又將bean標簽翻譯成了一個BeanDefinition,它是怎么翻譯的等下再說,先往下看
第29行,如果這個bean沒有指定beanName,那么就自己生成一個,一般是這個bean類的類名加上#在加一個數字,這個數字是從零開始的,這個數字要看這個bean是BeanFactory中的第幾個沒有寫beanName的bean了,他叫什么,這不是重點,我們一般也不會去寫個沒有beanName的bean,不寫beanName的情況一般是給spring通過類型來自動注入
下面開始講講它是怎么解析成BeanDefinition的
1 String className = null; 2 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { 3 className = ele.getAttribute(CLASS_ATTRIBUTE).trim();//獲得class屬性定義的className 4 } 5 6 try { 7 String parent = null; 8 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { 9 parent = ele.getAttribute(PARENT_ATTRIBUTE); //如果有parent屬性就獲取到parent屬性的值 10 } 11 AbstractBeanDefinition bd = createBeanDefinition(className, parent);//創建一個BeanDefinition對象 12 13 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); 14 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//如果這個bean元素有description子標簽,獲得他的值設置到BeanDefinition中 15 16 parseMetaElements(ele, bd);//解析元標簽<meta key="" value="">,當需要用到的時候,可以用過BeanDefinition的getAttribute(key)獲得 17 parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//解析bean標簽中是夠含有lookup-method標簽,如果有就設置到methodOverrides中 18 parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//解析replace-method標簽 19 20 parseConstructorArgElements(ele, bd);//解析構造器參數 21 parsePropertyElements(ele, bd);//解析property標簽 22 parseQualifierElements(ele, bd);//解析qualifier 23 24 bd.setResource(this.readerContext.getResource()); 25 bd.setSource(extractSource(ele)); 26 27 return bd;?
看到第13行,這個方法是用來解析bean定義的屬性的
1 public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, 2 BeanDefinition containingBean, AbstractBeanDefinition bd) { 3 4 if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {//如果存在singleton這個屬性,就解析,當不做任何處理,提示用戶過時了,應該使用scope來代替 5 error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); 6 } 7 else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {//如果存在scope屬性就取得取得他的值,并設置到BeanDefinition中 8 bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); 9 } 10 else if (containingBean != null) { 11 // Take default from containing bean in case of an inner bean definition. 12 bd.setScope(containingBean.getScope()); 13 } 14 15 if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { 16 bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); 17 } 18 19 String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); 20 if (DEFAULT_VALUE.equals(lazyInit)) { 21 lazyInit = this.defaults.getLazyInit(); 22 } 23 bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); 24 25 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); 26 bd.setAutowireMode(getAutowireMode(autowire)); 27 28 String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); 29 bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); 30 31 if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { 32 String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); 33 bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); 34 } 35 36 String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE); 37 if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) { 38 String candidatePattern = this.defaults.getAutowireCandidates(); 39 if (candidatePattern != null) { 40 String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern); 41 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); 42 } 43 } 44 else { 45 bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate)); 46 } 47 48 if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { 49 bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); 50 } 51 52 if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) { 53 String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE); 54 if (!"".equals(initMethodName)) { 55 bd.setInitMethodName(initMethodName); 56 } 57 } 58 else { 59 if (this.defaults.getInitMethod() != null) { 60 bd.setInitMethodName(this.defaults.getInitMethod()); 61 bd.setEnforceInitMethod(false); 62 } 63 } 64 65 if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) { 66 String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE); 67 bd.setDestroyMethodName(destroyMethodName); 68 } 69 else { 70 if (this.defaults.getDestroyMethod() != null) { 71 bd.setDestroyMethodName(this.defaults.getDestroyMethod()); 72 bd.setEnforceDestroyMethod(false); 73 } 74 } 75 76 if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { 77 bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); 78 } 79 if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { 80 bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); 81 } 82 83 return bd; 84 }將bean標簽中所有的屬性進行讀取,有定義的就讀過來設置到BeanDefinition中,如果沒有的自然是使用默認值,解析完bean標簽上的屬性后,自然還有解析bean
標簽里面的子標簽,這里選擇其中解析property解析下,下面是部分源碼
1 String propertyName = ele.getAttribute(NAME_ATTRIBUTE);//獲取property標簽上的那么屬性 2 if (!StringUtils.hasLength(propertyName)) { 3 error("Tag 'property' must have a 'name' attribute", ele); 4 return; 5 } 6 this.parseState.push(new PropertyEntry(propertyName)); 7 try { 8 if (bd.getPropertyValues().contains(propertyName)) { 9 error("Multiple 'property' definitions for property '" + propertyName + "'", ele); 10 return; 11 } 12 Object val = parsePropertyValue(ele, bd, propertyName); 13 PropertyValue pv = new PropertyValue(propertyName, val);//將屬性值和對應的value打包成一個PropertyValue 14 parseMetaElements(ele, pv); 15 pv.setSource(extractSource(ele)); 16 bd.getPropertyValues().addPropertyValue(pv);//將包含屬性值和值得propertyValue設置到BeanDefinition中我們看到第12行內部的部分代碼
1 if (hasRefAttribute) { 2 String refName = ele.getAttribute(REF_ATTRIBUTE); 3 if (!StringUtils.hasText(refName)) { 4 error(elementName + " contains empty 'ref' attribute", ele); 5 } 6 RuntimeBeanReference ref = new RuntimeBeanReference(refName); 7 ref.setSource(extractSource(ele)); 8 return ref; 9 } 10 else if (hasValueAttribute) { 11 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); 12 valueHolder.setSource(extractSource(ele)); 13 return valueHolder; 14 }第2行去獲得ref屬性的值,并且把這個值包裝成一個RuntimeBeanReference對象
第11行,如果不是個ref類型的值(value屬性指定的值)就被包裝成TypedStringValue類型的對象。
?
回到processBeanDefinition方法
1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 2 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 3 if (bdHolder != null) { 4 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 5 try { 6 // Register the final decorated instance. 7 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 8 } 9 catch (BeanDefinitionStoreException ex) { 10 getReaderContext().error("Failed to register bean definition with name '" + 11 bdHolder.getBeanName() + "'", ele, ex); 12 } 13 // Send registration event. 14 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 15 } 16 }第四行又對BeanDefinitionHolder做了些裝飾,這個方法的作用,主要是用來解析bean中嵌套的自定標簽,如<bean id="" class=""><mytag:test /></bean>
在這里順便再分析一下bean中construct-arg的解析方式
1 public void parseConstructorArgElement(Element ele, BeanDefinition bd) { 2 String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);//獲取index屬性的值 3 String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);//獲取type屬性的值 4 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//獲取name屬性的值 5 if (StringUtils.hasLength(indexAttr)) { 6 try { 7 int index = Integer.parseInt(indexAttr); 8 if (index < 0) { 9 error("'index' cannot be lower than 0", ele); 10 } 11 else { 12 try { 13 this.parseState.push(new ConstructorArgumentEntry(index)); 14 Object value = parsePropertyValue(ele, bd, null);//這段代碼和解析property標簽的方式一樣,對ref的值包裝成RuntimeBeanReference實例,value包裝成TypeStringValue的實例 15 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); 16 if (StringUtils.hasLength(typeAttr)) { 17 valueHolder.setType(typeAttr); 18 } 19 if (StringUtils.hasLength(nameAttr)) { 20 valueHolder.setName(nameAttr); 21 } 22 valueHolder.setSource(extractSource(ele)); 23 if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { 24 error("Ambiguous constructor-arg entries for index " + index, ele); 25 } 26 else { 27 bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); 28 } 29 } 30 finally { 31 this.parseState.pop(); 32 } 33 } 34 } 35 catch (NumberFormatException ex) { 36 error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); 37 } 38 } 39 else { 40 try { 41 this.parseState.push(new ConstructorArgumentEntry()); 42 Object value = parsePropertyValue(ele, bd, null); 43 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value); 44 if (StringUtils.hasLength(typeAttr)) { 45 valueHolder.setType(typeAttr); 46 } 47 if (StringUtils.hasLength(nameAttr)) { 48 valueHolder.setName(nameAttr); 49 } 50 valueHolder.setSource(extractSource(ele)); 51 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); 52 } 53 finally { 54 this.parseState.pop(); 55 } 56 } 57 }?
其實和解析property相同的套路,不同在與,property的是將返回回來的value用添加到了BeanDefinition的propertyValues屬性中,而構造器標簽對value的封裝使用了
ConstructorArgumentValues.ValueHolder值持有者來封裝,并把這個值存放到BeanDefinition的 indexedArgumentValue屬性中一切都準備就緒了,各種屬性都設置到為了BeanDefinition中了,那么剩下的就是注冊到BeanFactory中了
1 public static void registerBeanDefinition( 2 BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 3 throws BeanDefinitionStoreException { 4 5 // Register bean definition under primary name. 6 String beanName = definitionHolder.getBeanName(); 7 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); 8 9 // Register aliases for bean name, if any. 10 String[] aliases = definitionHolder.getAliases(); 11 if (aliases != null) { 12 for (String alias : aliases) { 13 registry.registerAlias(beanName, alias); 14 } 15 } 16 }
看到第7行的代碼有沒有似曾相識的感覺,我們在分析aop:config的時候就已經分析過了,如果忘記了往上翻,這里就不再重復說了,現在主要是看第13的代碼,別名的注冊
1 public void registerAlias(String name, String alias) { 2 Assert.hasText(name, "'name' must not be empty"); 3 Assert.hasText(alias, "'alias' must not be empty"); 4 if (alias.equals(name)) {//如果別名和beanName相同,那么就刪掉它,不需要別名 5 this.aliasMap.remove(alias); 6 } 7 else { 8 String registeredName = this.aliasMap.get(alias);//如果這個別名已經存在就拿出對應的beanName 9 if (registeredName != null) { 10 if (registeredName.equals(name)) {//如果對應的beanName是相同的,那么就無需再次注冊了 11 // An existing alias - no need to re-register 12 return; 13 } 14 if (!allowAliasOverriding()) {//如果不相等,就判斷是否允許別名覆蓋 15 throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + 16 name + "': It is already registered for name '" + registeredName + "'."); 17 } 18 } 19 checkForAliasCircle(name, alias); 20 this.aliasMap.put(alias, name); 21 } 22 }第19行進行別名循環依賴檢查,如果出現a能找到b,b又能找c,c又能找到a就會出錯
?
當xml中所有的標簽解析成BeanDefinition后,xml的解析工作也就結束了,接下來要做的事情就是創建bean了。
??
轉載于:https://www.cnblogs.com/honger/p/6819149.html
總結
以上是生活随笔為你收集整理的spring解析配置文件(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java BigDecimal Roun
- 下一篇: 《程序员修炼之道》笔记(八)