Spring Bean加载(一)
来源:互联网 发布:宾馆记账软件 编辑:程序博客网 时间:2024/06/04 19:26
前言
当前查看版本Spring 4.3.1.RELEASE,参考《Spring源码深度解析》
Spring加载Bean方式
该图是自己绘制的并不是顺序图!!!只是为了记录当前查看源码到什么位置仅供参考。看不清,可以找我要文件<.-.-.>
1、XmlBeanFactory
//过时的/** @deprecated */@Deprecatedpublic class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader;//主角 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); }}
2、ApplicationContext
上图是我自己绘制的ApplicationContext类图部分
XmlWebApplicationContext中的loadBeanDefinitions方法
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";//默认配置文件 public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";//配置文件前缀 public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";//配置文件后缀 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); this.initBeanDefinitionReader(beanDefinitionReader); this.loadBeanDefinitions(beanDefinitionReader); } protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) { } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String[] configLocations = this.getConfigLocations(); //调用父类方法获取配置文件路径,没有配置调用getDefaultConfigLocations()方法 if(configLocations != null) { String[] var3 = configLocations; int var4 = configLocations.length; for(int var5 = 0; var5 < var4; ++var5) { String configLocation = var3[var5]; reader.loadBeanDefinitions(configLocation); } } } protected String[] getDefaultConfigLocations() { return this.getNamespace() != null?new String[]{"/WEB-INF/" + this.getNamespace() + ".xml"}:new String[]{"/WEB-INF/applicationContext.xml"}; }
AbstractXmlApplicationContext中的loadBeanDefinitions方法
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory){ //同上面 } protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) { reader.setValidating(this.validating); } protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = this.getConfigResources(); //configResources = null if(configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = this.getConfigLocations(); if(configLocations != null) { reader.loadBeanDefinitions(configLocations); } } protected Resource[] getConfigResources() { return null; }
由上面代码可以看出主角是XmlBeanDefinitionReader类下面就开始了解这个类
父类AbstractBeanDefinitionReader类中loadBeanDefinitions重载方法
//调用子类的loadBeanDefinitions(Resource resource)方法 public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null"); int counter = 0; Resource[] var3 = resources; int var4 = resources.length; for(int var5 = 0; var5 < var4; ++var5) { Resource resource = var3[var5]; counter += this.loadBeanDefinitions((Resource)resource); } return counter; } //调用下面方法 public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException { return this.loadBeanDefinitions(location, (Set)null); } //代码那么长主要作用调用子类的loadBeanDefinitions(Resource resource)方法 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = this.getResourceLoader(); if(resourceLoader == null) { throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } else { int loadCount; if(!(resourceLoader instanceof ResourcePatternResolver)) { Resource resource = resourceLoader.getResource(location); loadCount = this.loadBeanDefinitions((Resource)resource); if(actualResources != null) { actualResources.add(resource); } if(this.logger.isDebugEnabled()) { this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } else { try { Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location); loadCount = this.loadBeanDefinitions(resources); if(actualResources != null) { Resource[] var6 = resources; int var7 = resources.length; for(int var8 = 0; var8 < var7; ++var8) { Resource resource = var6[var8]; actualResources.add(resource); } } if(this.logger.isDebugEnabled()) { this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException var10) { throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10); } } } } //调用本类的loadBeanDefinitions(String location)方法 public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException { Assert.notNull(locations, "Location array must not be null"); int counter = 0; String[] var3 = locations; int var4 = locations.length; for(int var5 = 0; var5 < var4; ++var5) { String location = var3[var5]; counter += this.loadBeanDefinitions(location);//调用第二个方法 }
XmlBeanDefinitionReader中loadBeanDefinitions重载方法
//作用:将Resource封装成EncodedResour(带编码的Resource)调用下一个方法 public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return this.loadBeanDefinitions(new EncodedResource(resource)); } //执行方法 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if(this.logger.isInfoEnabled()) { this.logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get(); //线程安全 ,但这里 currentResources应该本来就是线程安全的,所以推测不是为了线程安全。应该是为了线程能使用同一个 currentResources //来源http://blog.csdn.net/ykdsg/article/details/8674947 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 = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if(encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //调用doLoadBeanDefinitions方法 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; } } //调用下一方法 public int loadBeanDefinitions(InputSource inputSource) throws BeanDefinitionStoreException { return this.loadBeanDefinitions(inputSource, "resource loaded through SAX InputSource"); } //调用doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法 public int loadBeanDefinitions(InputSource inputSource, String resourceDescription) throws BeanDefinitionStoreException { return this.doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription)); }
以上就是XmlBeanDefinitionReader类的重载方法介绍
下面开始介绍执行方法了
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //获取Document对象 Document doc = this.doLoadDocument(inputSource, resource); //注册Bean return this.registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException var4) { throw var4; } catch (SAXParseException var5) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5); } catch (SAXException var6) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6); } catch (ParserConfigurationException var7) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7); } catch (IOException var8) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8); } catch (Throwable var9) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9); } } protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware()); //调用下面方法获取验证模式 } protected int getValidationModeForResource(Resource resource) { //获取xml文件验证模式XSD或DTD int validationModeToUse = this.getValidationMode();//1 if(validationModeToUse != 1) { return validationModeToUse; } else { //由代码自动识别判断 int detectedMode = this.detectValidationMode(resource); return detectedMode != 1?detectedMode:3; } } //调用XmlValidationModeDetector中detectValidationMode方法 protected int detectValidationMode(Resource resource) { if(resource.isOpen()) { throw new BeanDefinitionStoreException("Passed-in Resource [" + resource + "] contains an open stream: cannot determine validation mode automatically. Either pass in a Resource that is able to create fresh streams, or explicitly specify the validationMode on your XmlBeanDefinitionReader instance."); } else { InputStream inputStream; try { inputStream = resource.getInputStream(); } catch (IOException var5) { throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: cannot open InputStream. Did you attempt to load directly from a SAX InputSource without specifying the validationMode on your XmlBeanDefinitionReader instance?", var5); } try { //调用XmlValidationModeDetector中detectValidationMode方法 return this.validationModeDetector.detectValidationMode(inputStream); } catch (IOException var4) { throw new BeanDefinitionStoreException("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream.", var4); } } }
XmlValidationModeDetector代码节选
//常量 public static final int VALIDATION_NONE = 0; public static final int VALIDATION_AUTO = 1; public static final int VALIDATION_DTD = 2;//DTD校验 public static final int VALIDATION_XSD = 3;//XSD校验 //通过判断是否存在<!--DOCTYPE-->选择DTD或XSD private static final String DOCTYPE = "DOCTYPE"; private static final String START_COMMENT = "<!--"; private static final String END_COMMENT = "-->"; public int detectValidationMode(InputStream inputStream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); byte var4; try { boolean isDtdValidated = false; while(true) { String content; if((content = reader.readLine()) != null) { content = this.consumeCommentTokens(content); if(this.inComment || !StringUtils.hasText(content)) { continue; } if(this.hasDoctype(content)) { //存在DOCTYPE使用DTD校验 isDtdValidated = true; } else if(!this.hasOpeningTag(content)) { continue; } } //对应XSD和DTD常量 int var5 = isDtdValidated?2:3; return var5; } } catch (CharConversionException var9) { var4 = 1; } finally { reader.close(); } return var4; } private boolean hasDoctype(String content) { return content.contains("DOCTYPE"); }
DefaultDocumentLoader源码节选
/** * JAXP attribute used to configure the schema language for validation. */ private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; /** * JAXP attribute value indicating the XSD schema language. */ private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema"; @Override public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); } protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(namespaceAware); if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) { factory.setValidating(true); if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) { // Enforce namespace aware for XSD... //判断当前是否使用 xml schema 验证 factory.setNamespaceAware(true); try { factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE); } catch (IllegalArgumentException ex) { ParserConfigurationException pcex = new ParserConfigurationException( "Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " + "Upgrade to Apache Xerces (or Java 1.5) for full XSD support."); pcex.initCause(ex); throw pcex; } } } return factory; }
获取完Document对象后开始注册Bean
回到XmlBeanDefinitionReader的doLoadBeanDefinitions方法调用下面的方法
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { //创建DefaultBeanDefinitionDocumentReader BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //调用DefaultBeanDefinitionDocumentReader中registerBeanDefinitions方法 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
DefaultBeanDefinitionDocumentReader源码节选
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); //核心终于到了 doRegisterBeanDefinitions(root); }
由于贴太多代码篇幅太长,下篇
阅读全文
0 0
- Spring Bean加载(一)
- spring框架bean加载 一
- spring (一) 不同版本加载 bean 的方式
- spring源码阅读之Bean的加载(一)
- spring注解bean加载顺序问题(一)
- Spring源码之bean的加载(一)
- spring源代码之bean的加载(一)
- bean的加载(一)
- Spring(一)装配Bean
- Spring Bean加载过程(二)
- Spring-搞定bean加载
- spring bean 加载顺序
- spring bean 加载顺序
- spring延迟加载bean
- spring bean 加载顺序
- Spring 加载bean
- spring加载bean原理。
- spring动态加载Bean
- 一个疑问,模拟bootstrap获取webappclassloader的class却不成功,无语了。
- 容斥
- golang实现微信小程序支付通知
- 正则匹配简介
- ubuntu 下 docker 的container不能联网的问题
- Spring Bean加载(一)
- tomcat在conf/Catalina/localhost目录下配置虚拟目录
- httpurlconnectionget3
- 【脚本语言系列】关于Python基础知识多返回值,你需要知道的事
- include,require,include_once,require_once区别和性能对比
- 多年iOS开发经验总结(二)
- Springmvc 处理数据模型(三)
- ftpClient = new FtpClient(ip) 报错 cannot instantiate the type FtpClient
- 大型网站架构系列:负载均衡详解(1)