当前位置: 首页 > news >正文

做网站对服务器什么要求高/百度权重查询爱站网

做网站对服务器什么要求高,百度权重查询爱站网,企业只有建立自己的网站平台,网站开发保障合同IOC初始化总结1. 简介2. Resource 定位3. BeanDefinition 的载入和解析3.1 转换为 Document 对象3.2 对 Document 对象的解析3.3 标签解析4. 注册 BeanDefinition1. 简介 IOC容器的初始化过程分为三步骤:Resource 定位、BeanDefinition 的载入和解析,Bea…

IOC初始化总结

  • 1. 简介
  • 2. Resource 定位
  • 3. BeanDefinition 的载入和解析
    • 3.1 转换为 Document 对象
    • 3.2 对 Document 对象的解析
    • 3.3 标签解析
  • 4. 注册 BeanDefinition

1. 简介

       IOC容器的初始化过程分为三步骤:Resource 定位、BeanDefinition 的载入和解析,BeanDefinition 注册。

spring-201805281001
       1、Resource 定位。我们一般用外部资源(如xml文件)来描述 Bean对象,所以在初始化IOC 容器的第一步就是需要定位这个外部资源。

       2、BeanDefinition 的载入和解析。装载就是 BeanDefinition 的载入。BeanDefinitionReader 读取、解析 Resource 资源,也就是将用户定义的 Bean 表示成IOC 容器的内部数据结构:BeanDefinition。在IOC 容器内部维护着一个 BeanDefinition Map 的数据结构,在配置文件中每一个<bean>都对应着一个BeanDefinition对象。

       3、BeanDefinition 注册。向IOC容器注册在第二步解析好的 BeanDefinition,这个过程是通过 BeanDefinitionRegistery 接口来实现的。在IOC容器内部其实是将第二个过程解析得到的BeanDefinition注入到一个 HashMap容器中,IOC 容器就是通过这个HashMap来维护这些 BeanDefinition的。在这里需要注意的一点是这个过程并没有完成依赖注入,依赖注入是发生在应用第一次调用 getBean() 向容器索要 Bean时。当然我们可以通过设置预处理,即对某个Bean设置 lazyinit 属性,那么这个 Bean 的依赖注入就会在容器初始化的时候完成。

	ClassPathResource resource = new ClassPathResource("bean.xml");DefaultListableBeanFactory factory = new DefaultListableBeanFactory();XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);reader.loadBeanDefinitions(resource);

       1、ClassPathResource resource = new ClassPathResource("bean.xml");: 根据 Xml 配置文件创建 Resource 资源对象。ClassPathResourceResource 接口的子类,bean.xml 文件中的内容是我们定义的Bean信息。

       2、DefaultListableBeanFactory factory = new DefaultListableBeanFactory();创建一个 BeanFactoryDefaultListableBeanFactoryBeanFactory 的一个子类,BeanFactory 作为一个接口,其实它本身是不具有独立使用的功能的,而DefaultListableBeanFactory 则是真正可以独立使用的IOC 容器,它是整个 Spring IOC 的始祖,。

       3、XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);:创建 XmlBeanDefinitionReader读取器,用于载入BeanDefinition

       4、reader.loadBeanDefinitions(resource);:开启Bean 的载入和注册进程,完成后的 Bean 放置在 IOC 容器中。

2. Resource 定位

       Spring 为了解决资源定位的问题,提供了两个接口:ResourceResourceLoader,其中 Resource 接口是Spring统一资源的抽象接口,ResourceLoader 则是 Spring 资源加载的统一抽象。

       Resource 资源的定位需要ResourceResourceLoader 两个接口互相配合,在上面那段代码中 new ClassPathResource("bean.xml") 为我们定义了资源,那么 ResourceLoader 则是在什么时候初始化的呢?看 XmlBeanDefinitionReader 构造方法:

	public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {super(registry);}

       直接调用其父类 AbstractBeanDefinitionReader构造方法 :

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {Assert.notNull(registry, "BeanDefinitionRegistry must not be null");this.registry = registry;// Determine ResourceLoader to use.if (this.registry instanceof ResourceLoader) {this.resourceLoader = (ResourceLoader) this.registry;}else {this.resourceLoader = new PathMatchingResourcePatternResolver();}// Inherit Environment if possibleif (this.registry instanceof EnvironmentCapable) {this.environment = ((EnvironmentCapable) this.registry).getEnvironment();}else {this.environment = new StandardEnvironment();}}

       核心在于 resourceLoader 字段,如果设置了 ResourceLoader 则用设置的,否则使用 PathMatchingResourcePatternResolver,该类是一个集大成者的 ResourceLoader

3. BeanDefinition 的载入和解析

       reader.loadBeanDefinitions(resource); 开启 BeanDefinition的解析过程。如下:

	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));}

       在这个方法会将资源 resource 包装成一个 EncodedResource 实例对象,然后调用 loadBeanDefinitions() 方法,而将 Resource 封装成 EncodedResource 主要是为了对 Resource 进行编码,保证内容读取的正确性。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {String filename = encodedResource.getResource().getFilename();if (StringUtils.endsWithIgnoreCase(filename, ".xml")) {// 如果是以 xml 结尾,则以标准的xml解析方式去加载 resource 资源return this.standardXmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);} else {if (this.logger.isTraceEnabled()) {this.logger.trace("Loading Groovy bean definitions from " + encodedResource);}Closure<Object> beans = new Closure<Object>(this) {public Object call(Object... args) {GroovyBeanDefinitionReader.this.invokeBeanDefiningClosure((Closure)args[0]);return null;}};Binding binding = new Binding() {public void setVariable(String name, Object value) {if (GroovyBeanDefinitionReader.this.currentBeanDefinition != null) {GroovyBeanDefinitionReader.this.applyPropertyToBeanDefinition(name, value);} else {super.setVariable(name, value);}}};binding.setVariable("beans", beans);int countBefore = this.getRegistry().getBeanDefinitionCount();try {GroovyShell shell = new GroovyShell(this.getBeanClassLoader(), binding);shell.evaluate(encodedResource.getReader(), "beans");} catch (Throwable var7) {throw new BeanDefinitionParsingException(new Problem("Error evaluating Groovy script: " + var7.getMessage(), new Location(encodedResource.getResource()), (ParseState)null, var7));}int count = this.getRegistry().getBeanDefinitionCount() - countBefore;if (this.logger.isDebugEnabled()) {this.logger.debug("Loaded " + count + " bean definitions from " + encodedResource);}return count;}}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");if (logger.isTraceEnabled()) {logger.trace("Loading XML bean definitions from " + encodedResource);}// 获取正在被加载的 resources 资源Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();if (currentResources == null) {currentResources = new HashSet<>(4);this.resourcesCurrentlyBeingLoaded.set(currentResources);}// 如果当前加载的 resource 资源之前没有被加载过,则进行保存if (!currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");}try {// 将资源文件转为 InputStream 的 IO 流InputStream inputStream = encodedResource.getResource().getInputStream();try {// 从 InputStream 中得到 XML 的解析源InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 具体的读取过程return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}finally {inputStream.close();}}catch (IOException ex) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);}finally {// 加载完成后,将其删除currentResources.remove(encodedResource);if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}}

       从 encodedResource 源中获取 xml 的解析源,调用 doLoadBeanDefinitions() 执行具体的解析过程。

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {Document doc = doLoadDocument(inputSource, resource);int count = registerBeanDefinitions(doc, resource);if (logger.isDebugEnabled()) {logger.debug("Loaded " + count + " bean definitions from " + resource);}return count;}// 省略很多catch代码}

       在该方法中主要做两件事:

​ 1、根据 xml 解析源封装成相应的 Document 对象

​ 2、调用 registerBeanDefinitions() 开启 BeanDefinition 的解析注册过程。

3.1 转换为 Document 对象

       调用 doLoadDocument() 会将 Bean 的定义资源转换为 Document 对象。

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,getValidationModeForResource(resource), isNamespaceAware());
}

       loadDocument() 方法接受五个参数:

  • inputSource:加载 DocumentResource
  • entityResolver:解析文件的解析器
  • errorHandler:处理加载 Document 对象的过程的错误
  • validationMode:验证模式
  • namespaceAware:命名空间支持。如果要提供对 XML 名称空间的支持,则为true

       loadDocument() 在类 DefaultDocumentLoader 中提供了实现,如下:

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);// 解析 Spring 的 Bean 定义资源return builder.parse(inputSource);
}

       到这里,就已经将定义的 Bean 资源文件,载入并转换为 Document 对象了,那么下一步就是如何将其解析为 Spring IOC 管理的 Bean 对象并将其注册到容器中。这个过程有方法 registerBeanDefinitions() 实现。如下:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {// 创建 BeanDefinitionDocumentReader 来对 xml 格式的BeanDefinition 解析BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();// 获得容器中注册的Bean数量int countBefore = getRegistry().getBeanDefinitionCount();// 解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口,// 具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成documentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;
}

       首先创建BeanDefinition 的解析器 BeanDefinitionDocumentReader,然后调用 documentReader.registerBeanDefinitions() 开启解析过程,这里使用的是委派模式,具体的实现由子类 DefaultBeanDefinitionDocumentReader 完成。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {// 获得XML描述符this.readerContext = readerContext;logger.debug("Loading bean definitions");// 获得Document的根元素Element root = doc.getDocumentElement();// 解析根元素doRegisterBeanDefinitions(root);
}

3.2 对 Document 对象的解析

       从 Document 对象中获取根元素 root,然后调用 doRegisterBeanDefinitions() 开启真正的解析过程。

protected void doRegisterBeanDefinitions(Element root) {BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(getReaderContext(), root, parent);// 省略部分代码preProcessXml(root);parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;
}

       preProcessXml()postProcessXml() 为前置、后置增强处理,目前 Spring中都是空实现, parseBeanDefinitions() 是对根元素 root 的解析注册过程。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {// Bean定义的Document对象使用了Spring默认的XML命名空间if (delegate.isDefaultNamespace(root)) {// 获取Bean定义的Document对象根元素的所有子节点NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);// 获得Document节点是XML元素节点if (node instanceof Element) {Element ele = (Element) node;// Bean定义的Document的元素节点使用的是Spring默认的XML命名空间if (delegate.isDefaultNamespace(ele)) {// 使用Spring的Bean规则解析元素节点(默认解析规则)parseDefaultElement(ele, delegate);}else {// 没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点delegate.parseCustomElement(ele);}}}}else {// Document 的根节点没有使用Spring默认的命名空间,则使用用户自定义的解析规则解析delegate.parseCustomElement(root);}
}

       迭代 root 元素的所有子节点,对其进行判断,若节点为默认命名空间,则调用 parseDefaultElement() 开启默认标签的解析注册过程,否则调用 parseCustomElement() 开启自定义标签的解析注册过程。

3.3 标签解析

       若定义的元素节点使用的是Spring 默认命名空间,则调用 parseDefaultElement() 进行默认标签解析,如下:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {// 如果元素节点是<Import>导入元素,进行导入解析if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}// 如果元素节点是<Alias>别名元素,进行别名解析else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}// 如果元素节点<Bean>元素,则进行Bean解析注册else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}// // 如果元素节点<Beans>元素,则进行Beans解析else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}
}

       对于自定义标签则由 parseCustomElement() 负责解析。

public BeanDefinition parseCustomElement(Element ele) {return parseCustomElement(ele, null);
}public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

       获取节点的 namespaceUri,然后根据该 namespaceuri获取相对应的 Handler,调用 Handlerparse() 方法即完成自定义标签的解析和注入。

4. 注册 BeanDefinition

       经过上面的解析,则将 Document 对象里面的Bean标签解析成了一个个的 BeanDefinition,下一步则是将这些BeanDefinition 注册到IOC 容器中。动作的触发是在解析 Bean 标签完成后,如下:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// Send registration event.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}
}

       调用 BeanDefinitionReaderUtils.registerBeanDefinition() 注册,其实这里面也是调用 BeanDefinitionRegistryregisterBeanDefinition()来注册 BeanDefinition ,不过最终的实现是在DefaultListableBeanFactory 中实现,如下:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {// 省略一堆校验BeanDefinition oldBeanDefinition;oldBeanDefinition = this.beanDefinitionMap.get(beanName);// 省略一堆 ifthis.beanDefinitionMap.put(beanName, beanDefinition);
}
else {if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)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 {// Still in startup registration phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;
}if (oldBeanDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);
}
}
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

       这段代码最核心的部分是这句 this.beanDefinitionMap.put(beanName, beanDefinition) ,所以注册过程也不是那么的高大上,就是利用一个 ConcurrentHashMap的集合对象来存放,key 是 beanName,value 是 BeanDefinition

       至此,整个IOC 的初始化过程就已经完成了,从 Bean 资源的定位,转换为 Document 对象,接着对其进行解析,最后注册到IOC容器中,都已经完美地完成了。现在IOC 容器中已经建立了整个 Bean 的配置信息,这些 Bean可以被检索、使用、维护,他们是控制反转的基础,是后面注入 Bean的依赖。

在这里插入图片描述

http://www.jmfq.cn/news/5153887.html

相关文章:

  • 如何注册域名免费/微博关键词排名优化
  • 网站建设一站通.网站模板一站平台/培训心得体会万能模板
  • 程序员常用的编程软件/seo快速排名培训
  • 移动网站建设方案/seo数据
  • vs做网站mvc/八大营销方式有哪几种
  • 常州网站建设网站/seo工作前景如何
  • 顺的网站建设精英/seo文章代写平台
  • 南京网站建设价格/seo网站优化推广教程
  • 平面设计包括什么/seo综合查询网站源码
  • 如何做电商网站视频/800元做小程序网站
  • 我做网站价格/重庆seo和网络推广
  • 杭州 seo网站建设 网络服务/网络销售的工作内容
  • 网站需要做实名认证如何做/建站模板哪个好
  • 做网站需要哪些资料/近期国际新闻
  • 做网站游燕/快速优化网站排名的方法
  • dede阿里百秀网站源码/百度我的订单查询
  • 网站开发公司好开发客户吗/百度云群组
  • 南阳企业网站建设公司/重庆seo推广外包
  • 网站充值页面模板/百度搜索一下
  • 网站建设武汉/企业网站优化服务公司
  • 试玩平台怎么做网站/泰安seo培训
  • 门户网站模板 免费/友情链接百科
  • 网站制作及实现/武汉网站推广优化
  • 如何用域名建网站/百度查询关键词排名工具
  • 主机屋怎么做网站/百度网页版 入口
  • 车工订单网站/信息流优化师需要具备哪些能力
  • 长沙哪个公司做网站/推手平台哪个靠谱
  • 石家庄网站建设推广公司报价/永久免费的电销外呼系统
  • 深圳做网站推广的公司/北京百度推广电话号码
  • 注册网站的步骤/哪有网页设计公司