04-spring配置文件加载过程

文章目录

  • spring配置文件加载过程

spring配置文件加载过程

在这里插入图片描述在这里插入图片描述

调用refresh方法中obtainFreshBeanFactory()

	@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 这里主要是做的是容器刷新前的准备工作* 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中* 5、准备监听器和事件的集合对象,默认为空的集合*/prepareRefresh();// Tell the subclass to refresh the internal bean factory.// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.// 调用各种beanFactory处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲initMessageSource();// Initialize event multicaster for this context.// 初始化事件监听多路广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 留给子类来初始化其他的beanonRefresh();// Check for listener beans and register them.// 在所有注册的bean中查找listener bean,注册到消息广播器中registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 初始化剩下的单实例(非懒加载的)finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.// 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件beandestroyBeans();// Reset 'active' flag.// 重置active标志cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

在obtainFreshBeanFactory中

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中refreshBeanFactory();// 返回当前实体的beanFactory属性return getBeanFactory();}

这个方法主要负责初始化BeanFactory以及返回beanFactory中的属性
在refreshBeanFactory中对xml文件进行读取,并且将解析到的bean记录在当前的beanFactory中

@Overrideprotected final void refreshBeanFactory() throws BeansException {// 如果存在beanFactory,则销毁beanFactoryif (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建DefaultListableBeanFactory对象DefaultListableBeanFactory beanFactory = createBeanFactory();// 为了序列化指定id,可以从id反序列化到beanFactory对象beanFactory.setSerializationId(getId());// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖customizeBeanFactory(beanFactory);// 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析loadBeanDefinitions(beanFactory);this.beanFactory = beanFactory;}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {// 如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性,是否允许覆盖同名称的不同定义的对象if (this.allowBeanDefinitionOverriding != null) {beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// 如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性,是否允许bean之间存在循环依赖if (this.allowCircularReferences != null) {beanFactory.setAllowCircularReferences(this.allowCircularReferences);}}

初始化beanFactory的主要过程
1、首先判断是否已经存在beanFactory,若存在则销毁beanFactory
2、创建默认的beanFactory,这里是创建的是DefaultListableBeanFactory对象
3、指定beanFactory的id
4、定制beanFactory,这里可以对这个方法重写,默认是看是否允许覆盖同名定义的对象以及是否允许循环依赖
5、初始化beanDefintions,这哥方法主要是初始化documentRander,读取、解析xml文件,解析默认的命名空间以及自定义的标签
主要逻辑在loadBeanDefinitions(beanFactory); 方法中,从这里开始以下的主要逻辑都是loadBeanDefinitions这个方法

	@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.// 创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's//		// resource loading environment.//		// 给reader对象设置环境对象beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);//里面是调用的toString方法,在debug的时候完成加载。正常这里是不加载的,这里主要用于使用工具是加载本地映射beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.//  初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证。适配器模式initBeanDefinitionReader(beanDefinitionReader);// 开始完成beanDefinition的加载loadBeanDefinitions(beanDefinitionReader);}

initBeanDefinitionReader(beanDefinitionReader); 这个方法主要是设置是否开启校验,设置了一个validating属性

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// 以Resource的方式获得配置文件的资源位置Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}// 以String的形式获得配置文件的位置String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}}

这里主要有两种加载方式,一个是基于Resource去获取资源位置,一个是String去获取资源位置这里使用的是第二种

	@Overridepublic int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int count = 0;for (String location : locations) {count += loadBeanDefinitions(location);}return count;}

在这里插入图片描述

	@Overridepublic int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {return loadBeanDefinitions(location, null);}
	public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {//此处获取resourceLoader对象ResourceLoader resourceLoader = getResourceLoader();if (resourceLoader == null) {throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");}if (resourceLoader instanceof ResourcePatternResolver) {// Resource pattern matching available.try {// 调用DefaultResourceLoader的getResource完成具体的Resource定位Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);int count = loadBeanDefinitions(resources);if (actualResources != null) {Collections.addAll(actualResources, resources);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");}return count;}catch (IOException ex) {throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);}}else {// Can only load single resources by absolute URL.Resource resource = resourceLoader.getResource(location);int count = loadBeanDefinitions(resource);if (actualResources != null) {actualResources.add(resource);}if (logger.isTraceEnabled()) {logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");}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);}// 通过属性来记录已经加载的资源Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();if (!currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");}// 从encodedResource中获取已经封装的Resource对象并再次从Resource中获取其中的inputStreamtry (InputStream inputStream = encodedResource.getResource().getInputStream()) {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 逻辑处理的核心步骤return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}catch (IOException ex) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);}finally {currentResources.remove(encodedResource);if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}}

这里 doLoadBeanDefinitions 此方法是核心处理逻辑

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 此处获取xml文件的document对象,这个解析过程是由documentLoader完成的,// 解析过程: String[] -string-Resource[]- resource,// 最终将resource读取成一个document文档,根据文档的节点信息封装成一个个的BeanDefinition对象Document doc = doLoadDocument(inputSource, resource);int count = registerBeanDefinitions(doc, resource);if (logger.isDebugEnabled()) {logger.debug("Loaded " + count + " bean definitions from " + resource);}return count;}catch (BeanDefinitionStoreException ex) {throw ex;}catch (SAXParseException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);}catch (SAXException ex) {throw new XmlBeanDefinitionStoreException(resource.getDescription(),"XML document from " + resource + " is invalid", ex);}catch (ParserConfigurationException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Parser configuration exception parsing XML from " + resource, ex);}catch (IOException ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"IOException parsing XML document from " + resource, ex);}catch (Throwable ex) {throw new BeanDefinitionStoreException(resource.getDescription(),"Unexpected exception parsing XML document from " + resource, ex);}}

在这里插入图片描述

doLoadDocument 此方法是将xml文件读取解析为一个document对象

	@Overridepublic Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {//创建document构建工厂DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);if (logger.isTraceEnabled()) {logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");}//创建docuemnt构建对象DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);//解析流资源,获取document对象return builder.parse(inputSource);}

registerBeanDefinitions 此方法是注册bean定义信息

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {// 对xml的beanDefinition进行解析BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();int countBefore = getRegistry().getBeanDefinitionCount();// 完成具体的解析过程documentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}
	@Overridepublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;doRegisterBeanDefinitions(doc.getDocumentElement());}
	protected void doRegisterBeanDefinitions(Element root) {// Any nested <beans> elements will cause recursion in this method. In// order to propagate and preserve <beans> default-* attributes correctly,// keep track of the current (parent) delegate, which may be null. Create// the new (child) delegate with a reference to the parent for fallback purposes,// then ultimately reset this.delegate back to its original (parent) reference.// this behavior emulates a stack of delegates without actually necessitating one.BeanDefinitionParserDelegate parent = this.delegate;this.delegate = createDelegate(getReaderContext(), root, parent);if (this.delegate.isDefaultNamespace(root)) {String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);if (StringUtils.hasText(profileSpec)) {String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);// We cannot use Profiles.of(...) since profile expressions are not supported// in XML config. See SPR-12458 for details.if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {if (logger.isDebugEnabled()) {logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +"] not matching: " + getReaderContext().getResource());}return;}}}preProcessXml(root);parseBeanDefinitions(root, this.delegate);postProcessXml(root);this.delegate = parent;}

parseBeanDefinitions 此方法是解析bean定义信息,这里的preProcessXml以及postProcessXml是对解析bean定义信息前后可进行扩展

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {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)) {parseDefaultElement(ele, delegate);}else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}
	public static final String NESTED_BEANS_ELEMENT = "beans";public static final String ALIAS_ELEMENT = "alias";public static final String NAME_ATTRIBUTE = "name";public static final String ALIAS_ATTRIBUTE = "alias";public static final String IMPORT_ELEMENT = "import";public static final String RESOURCE_ATTRIBUTE = "resource";public static final String PROFILE_ATTRIBUTE = "profile";private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}}

在这里插入图片描述

这里调用的是 processBeanDefinition

	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {// beanDefinitionHolder是beanDefinition对象的封装类,封装了BeanDefinition,bean的名字和别名,用它来完成向IOC容器的注册// 得到这个beanDefinitionHolder就意味着beandefinition是通过BeanDefinitionParserDelegate对xml元素的信息按照spring的bean规则进行// 解析得到的BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.// 向ioc容器注册解析得到的beandefinition的地方BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// Send registration event.// 在beandefinition向ioc容器注册完成之后,发送消息getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}}
	public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// Register bean definition under primary name.// 使用beanName做唯一标识注册String beanName = definitionHolder.getBeanName();registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// Register aliases for bean name, if any.// 注册所有的别名String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}}
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {Assert.hasText(beanName, "Bean name must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");if (beanDefinition instanceof AbstractBeanDefinition) {try {// 注册前的最后一个校验,这里的检验不同于之前的xml文件校验,主要是对应abstractBeanDefinition属性的methodOverrides校验,// 检验methodOverrides是否与工厂方法并存或者methodoverrides对应的方法根本不存在((AbstractBeanDefinition) beanDefinition).validate();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,"Validation of bean definition failed", ex);}}BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);// 处理注册已经注册的beanName情况if (existingDefinition != null) {// 如果对应的beanName已经注册且在配置中配置了bean不允许被覆盖,则抛出异常if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);}else if (existingDefinition.getRole() < beanDefinition.getRole()) {// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTUREif (logger.isInfoEnabled()) {logger.info("Overriding user-defined bean definition for bean '" + beanName +"' with a framework-generated bean definition: replacing [" +existingDefinition + "] with [" + beanDefinition + "]");}}else if (!beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {logger.debug("Overriding bean definition for bean '" + beanName +"' with a different definition: replacing [" + existingDefinition +"] with [" + beanDefinition + "]");}}else {if (logger.isTraceEnabled()) {logger.trace("Overriding bean definition for bean '" + beanName +"' with an equivalent definition: replacing [" + existingDefinition +"] with [" + beanDefinition + "]");}}this.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;removeManualSingletonName(beanName);}}else {// Still in startup registration phase// 注册beanDefinitionthis.beanDefinitionMap.put(beanName, beanDefinition);// 记录beanNamethis.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}if (existingDefinition != null || containsSingleton(beanName)) {// 重置所有beanName对应的缓存resetBeanDefinition(beanName);}else if (isConfigurationFrozen()) {clearByTypeCache();}}

在这里插入图片描述

最终将bena定义信息注册到ioc中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/26925.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我们如何在 Elasticsearch 8.6、8.7 和 8.8 中加速数据摄入

作者&#xff1a;Adrien Grand, Joe Gallo, Tyler Perkins 正如你们中的一些人已经注意到的&#xff0c;Elasticsearch 8.6、8.7 和 8.8 在各种数据集上带来了良好的索引加速&#xff0c;从简单的关键字到繁重的 KNN 向量&#xff0c;以及摄取管道繁重的摄取工作负载。 摄取涉及…

推荐10个Flutter开源项目

作为跨平台应用开发的领头羊,Flutter从已发布就受到广大开发者的追捧。使用Flutter技术开发的应用不仅体验上无限接近原生应用,在开发效率上也是其他技术无法比拟的。随着其开发者社区的不断壮大,Flutter生态系统已经相当强大,并且众多开源应用程序也相继诞生。这些开源应用…

ceph--cephFS的使用

ceph分布式存储—cephFS的使用 1、cephfs的概念 ceph FS 即 ceph filesystem&#xff0c;可以实现文件系统共享功能,客户端通过 ceph 协议挂载并使 用 ceph 集群作为数据存储服务器。 Ceph FS 需要运行 Meta Data Services(MDS)服务&#xff0c;其守护进程为 ceph-mds&#x…

MongoDB

安装 数据存放路径&#xff1a;D:\data\db 安装目录&#xff1a;D:\MongoDB\mongodb-windows-x86_64-5.0.19\mongodb-win32-x86_64-windows-5.0.19\bin 配置环境变量 开启服务端&#xff0c;客户端 # 开启服务端&#xff0c;指定数据存放路径 mongod --dbpath D:\data\…

【HCIA】11.ACL与NAT地址转换

ACL 通过ACL可以实现对网络中报文流的精确识别和控制&#xff0c;达到控制网络访问行为、防止网络攻击和提高网络带宽利用率的目的。 ACL是由permit或deny语句组成的一系列有顺序的规则的集合&#xff1b;它通过匹配报文的相关字段实现对报文的分类。ACL是能够匹配一个IP数据包…

vue 通过多组复选框来过滤数据

1.通过if else 来筛选数据 <template> <div><div><label><input type"checkbox" v-model"checkedNames" value"北京"> 北京</label><label><input type"checkbox" v-model"chec…

【Web UI自动化测试】Web UI自动化测试之框架篇(全网最全)

本文大纲截图&#xff1a; UnitTest框架&#xff1a; PyTest框架&#xff1a; 框架&#xff1a; 框架英文单词 framework&#xff0c;为解决一类事情的功能的集合。需要按照框架的规定&#xff08;套路&#xff09;去书写代码。 一、UnitTest框架介绍【文末分享自动化测试学习…

【iOS】—— 编译链接

【iOS】—— 编译链接 文章目录 【iOS】—— 编译链接编译流程预处理&#xff08;预编译Prepressing&#xff09;编译&#xff08;Compilation&#xff09;汇编&#xff08;Assembly&#xff09;链接&#xff08;Linking&#xff09; 编译流程 编译流程分为四步 预处理&#…

Windows搭建Nginx实现RTMP转为HLS流

所需软件 nginx-1.7.11.3-Gryphon&#xff08;这个包含必须的RTMP模块&#xff0c;普通的Ngxin没有这个&#xff09;ffmpegVLC 配置Nginx 1为Nginx配置RTMP和HLS 这里定义了一个叫live的RTMP路径。同时设置其开启HLS功能&#xff0c;那么所有推送到这个地址的RTMP流都会自动生…

csapp 深入理解计算机系統 笔记

csapp 深入理解计算机系統 笔记 参考lab 第1章&#xff1a;计算机系统漫游第 2 章&#xff1a;信息的表示和处理Data Lab 第03章&#xff1a;程序的机器级表示Bomb Lab 参考 计算机速成课 | Crash Course 字幕组 (全40集 2018-5-1 精校完成)csapp重点解读深入理解计算机系統 c…

讯为RK3568开发板到手编译buildroot系统入坑一

从事单片机开发多年一直想买一个开发板学习Linux系统&#xff0c;这次狠心花了800多打样买了一个讯为的RK3568低配。裸板配置。 因为讯为没有编译系统的视频教程&#xff0c;只有文档的教程&#xff0c;而且只有瑞芯微官方带的Linux源码中的系统编译后文档教程。像ubuntu是没有…

安装hive数据仓库

部署hive数据库 环境准备 需要安装部署完成的Hadoop的环境如果不会搭建的可以参考&#xff1a; 安装mysql 卸载Centos7自带的mariadb rpm -qa|grep mariadbrpm -e mariadb-libs-5.5.64-1.el7.x86_64 --nodepsrpm -qa|grep mariadb mariadb-libs-5.5.64-1.el7.x86_64是使用…