解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析
一. 前言
Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别。本篇就以BeanFactory基础容器接口的默认实现类XmlBeanFactory启动流程分析来入门Spring源码的学习。
二. 概念要点
1. 概念定义
- BeanDefinition:Bean元数据描述,Bean在Spring IOC容器中的抽象,是Spring的一个核心概念
- DefaultListableBeanFactory : Spring IOC容器的实现,可以作为一个独立使用的容器, Spring IOC容器的始祖
- XmlBeanFactory:继承自DefaultListableBeanFactory,与其不同点在于XmlBeanFactory中使用了自定义的XML读取器XmlBeanDefinitionReader,实现了个性化的BeanDefinitionReader读取
- ApplicationContext: 高级容器定义接口,基于BeanFactory添加了扩展功能,如ResourceLoader、MessageSource、ApplicationEventPublisher等
2. 糟糕!XmlBeanFactory被废弃了
对Spring有些了解的应该XmlBeanFactory已经过时了。没错,本篇要讲的XmlBeanFactory在Spring3.1这个很久远版本就开始过时了。
@deprecated as of Spring 3.1 in favor of {@link DefaultListableBeanFactory}

取而代之的写法如下
ClassPathResource resource=new ClassPathResource("spring-config.xml");
DefaultListableBeanFactory beanFactory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader=new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.loadBeanDefinitions(resource);
概括
DefaultListableBeanFactory + XmlBeanDefinitionReader 取代了 XmlBeanFactory容器的创建和初始化,可以联想到通过组合的方式灵活度是比XmlBeanFactory高的,针对不同的资源读取组合的方式只需替换不同的读取器BeanDefinitionReader就可以了,而XmlBeanFactory中的读取器XmlBeanDefinitionReader限定其只能读取XML格式的文件资源,所以至于XmlBeanFactory被废弃的原因可想而知。
3. XmlBeanFactory?!XML,你会XML解析吗?
<?xml version="1.0" encoding=" UTF-8" standalone="yes"?><root>
<code>0</code>
<message>调用成功</message>
</root>
附上DOM4J解析的代码
String xml="<?xml version="1.0" encoding=" UTF-8" standalone="yes"?><root>n" +"<code>0</code>n" +"<message>调用成功</message>n" +"</root>";
Document document = DocumentHelper.parseText(xml);
Element root = document.getRootElement();
String code = root.elementText("code");
String message =root.elementText("message");

XML文档被解析成DOM树,其中Document是整个DOM的根节点,root为根元素,由根元素一层一层向下解析element元素,容器启动解析XML流程就是这样。
三. XmlBeanFactory启动流程分析
XmlBeanFactory容器启动就两行代码
ClassPathResource resource = new ClassPathResource("spring-config.xml");
XmlBeanFactory beanFactory = new XmlBeanFactory(resource);
怎么样?看似简单就证明了Java封装的强大,但背后藏了太多。 这里就送上XmlBeanFactory启动流程图,对应的就是上面的两行代码。

这是啥?!看得头晕的看官老爷们别急着给差评啊(瑟瑟发抖中)。这里精简下,想快速理解的话直接看精简版后的,想深入到细节建议看下上面的时序图。

整个就是bean的加载阶段。通过解析XML中的标签元素生成beanDefinition注册到beanDefinitionMap中。
四. XmlBeanFactory启动源码解析
按照XmlBeanFactory启动流程的先后顺序整理的关键性代码索引列表,其中一级索引为类,二级索引对应其类下的方法。符号 ---▷表示接口的实现。建议可以观察方法索引的参数变化(资源转换)来分析整个流程,来加深对流程的理解。
- XmlBeanFactoryXmlBeanFactory(Resource resource)
- XmlBeanDefinitionReaderloadBeanDefinitions(Resource resource)doLoadBeanDefinitions(InputSource inputSource, Resource resource)registerBeanDefinitions(Document doc, Resource resource)
- DefaultBeanDefinitionDocumentReader ---▷ BeanDefinitionDocumentReaderregisterBeanDefinitions(Document doc, XmlReaderContext readerContext)doRegisterBeanDefinitions(Element root)parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
- BeanDefinitionParserDelegateparseBeanDefinitionElement(Element ele)decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder originalDef,...)
- DefaultListableBeanFactory ---▷ BeanDefinitionRegistryregisterBeanDefinition(String beanName, BeanDefinition beanDefinition)
好了,当你心里对这个流程有个大概的样子之后,这里就可以继续走下去。建议还是很模糊的同学自重,避免走火入魔想对我人身攻击的。下面就每个方法重要的点一一解析,严格按照方法的执行先后顺序来说明。
1.1 XmlBeanFactory(Resource resource)
功能概述: XmlBeanFactory的构造方法,整个容器启动的入口,完成bean工厂的实例化和BeanDefinition加载(解析和注册)。
/*** XmlBeanFactory**/
public XmlBeanFactory(Resource resource) throws BeansException {this(resource, null);
}public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {super(parentBeanFactory); // 加载(解析注册)BeanDefinitionthis.reader.loadBeanDefinitions(resource);
}
知识点:
- Resource:Resource接口是Spring资源访问策略的抽象,,而具体的资源访问方式由其实现类完成,如类路径资源(ClassPathResource)、文件(FileSystemResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource),根据不同的类型的资源使用对应的访问策略,明明白白的策略模式。
2.1 loadBeanDefinitions(Resource resource)
功能概述: 上面根据ClassPathResource资源访问策略拿到了资源Resource,这里将Resource进行特定的编码处理,然后将编码后的Resource转换成SAX解析XML文件所需要的输入源InputSource。
/*** XmlBeanDefinitionReader**/
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {// 把从XML文件读取的Resource资源进行编码处理return loadBeanDefinitions(new EncodedResource(resource));
}/*** XmlBeanDefinitionReader**/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {...// 完成resource->inputStream->inputSource转换,使用SAX方式接收输入源InputSource解析XMLtry (InputStream inputStream = encodedResource.getResource().getInputStream()) {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// 执行加载BeanDefinitionreturn doLoadBeanDefinitions(inputSource, encodedResource.getResource());}...
}
知识点:
- XML解析两种方式:SAX(Simple API for XML)和DOM(Document Object Model),区别在于SAX按照顺序逐行读取,查找到符合条件即停止,只能读不能修改,适合解析大型XML;DOM则是一次性读取到内存建立树状结构,占用内存,不仅能读还能修改XML。Spring采用的SAX方式来解析XML。
2.2 doLoadBeanDefinitions(InputSource inputSource, Resource resource)
功能概述: 获取DOM Document对象,XmlBeanDefinitionReader本身没有对文档读取的能力,而是委托给DocumentLoader的实现类DefaultDocumentLoader去读取输入源InputResource从而得到Document对象。获得Document对象后,接下来就是BeanDefinition的解析和注册。
/*** XmlBeanDefinitionReader**/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {...try {// inputSource->DOM DocumentDocument doc = doLoadDocument(inputSource, resource);int count = registerBeanDefinitions(doc, resource);return count;}...
}
知识点:
- Document是DOM的根节点,提供对文档数据访问的入口。
2.3 registerBeanDefinitions(Document doc, Resource resource)
功能概述: 解析DOM Document成容器的内部数据接口BeanDefinition并注册到容器内部。
/*** XmlBeanDefinitionReader**/
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();// 已注册的BeanDefinition的数量int countBefore = getRegistry().getBeanDefinitionCount();// DOM Document->BeanDefinition,注册BeanDefinition至容器documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 返回此次注册新增的BeanDefinition数量return getRegistry().getBeanDefinitionCount() - countBefore;
}
知识点:
- BeanDefinitionDocumentReader是接口,实际完成对DOM Document解析的是其默认实现类DefaultBeanDefinitionDoucumentReade。
- createReaderContext(resource)创建XmlReaderContext上下文,包含了XmlBeanDefinitionReader读取器和NamespaceHandlerResolver 命名空间解析器。
3.1 registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
功能概述: 在此之前一直 是XML加载解析的准备阶段,在获取到Document对象之后就开始真正的解析了。
/*** DefaultBeanDefinitionDocumentReader**/
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;doRegisterBeanDefinitions(doc.getDocumentElement());
}
3.2 doRegisterBeanDefinitions(Element root)
功能概述: 解析Element,
DefaultBeanDefinitionDoucumentReader同样不具有解析Element的能力,委托给
BeanDefinitionParserDelegate执行。
/*** DefaultBeanDefinitionDocumentReader**/
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的一个扩展点,后面有机会可以深入下细节。
3.3 parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
功能概述: 判别XML中Bean的声明标签是默认的还是自定义的,执行不同的解析逻辑。对于根节点或者子节点是默认命名空间采用parseDefaultElement,否则使用parseCustomElement对自定义命名空间解析。
/*** DefaultBeanDefinitionDocumentReader**/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate){// 对beans的处理if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {// 对默认的Bean标签解析parseDefaultElement(ele, delegate);}else {// 对自定义的Bean标签解析delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}
}
知识点:
- Spring中XML有两大类Bean的声明标签默认声明标签:<bean id="userService" class="com.fly4j.service.impl.UserServiceImpl"/>自定义声明标签: ·<tx: annotation-driven />
- 怎么区分是默认命名空间还是自定义命名空间?通过node.getNamespaceURI()获取命名空间并和Spring中固定的命名空间http://www.springframework.org/schema/beans进行比对,如果一致则默认,否则自定义。
3.4 parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
功能概述: 上面说到Spring标签包括默认标签和自定义标签两种。解析这两种方式分别不同。以下就默认标签进行说明
BeanDefinitionParseDelegate对Bean标签元素的解析过程。
/*** DefaultBeanDefinitionDocumentReader**/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {// import标签importBeanDefinitionResource(ele);}else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {// alias标签processAliasRegistration(ele);}else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {// bean标签processBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// beans标签doRegisterBeanDefinitions(ele);}
}
知识点:
- Spring的4种默认标签举例:import <import resource="spring-config.xml"/>alias<bean id="userService" class="com.fly4j.service.impl.UserServiceImpl"></bean>
<alias name="userService" alias="user" />bean<beans>
<bean id="userService" class="com.fly4j.service.impl.UserServiceImpl"></bean>
</beans>beans<beans>
<bean id="userService" class="com.fly4j.service.impl.UserServiceImpl"></bean>
</beans>
3.5 processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
功能概述: 在4中默认标签当中,其中核心的是对bean标签的解析。以下就对bean标签的解析来看解析过程。
/*** DefaultBeanDefinitionDocumentReader**/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate){BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // 参考4.1源码if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); // 参考4.2源码try {BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); // 参考5.1源码}...// Send registration event.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}
}
流程解读:
- DefaultBeanDefinitionDocumentReader委托BeanDefinitionParseDelegate的parseBeanDefinitionElement方法进行标签元素的解析。解析后返回BeanDefinitionHolder实例bdHolder,bdHolder实例包含了配置文件中的id、name、alias之类的属性。
- 返回的bdHolder不为空时,标签元素如果有自定义属性和自定义子节点,还需要再次对以上两个标签解析。具体逻辑参考4.2小节源码。
- 解析完成后,对bdHolder进行注册,使用BeanDefinitionReaderUtils.registerBeanDefinition()方法。具体逻辑参考5.1小节源码。
- 发出响应事件,通知相关监听器,bean已经解析完成。
4.1 registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
功能概述: 通过
BeanDefinitionParseDelegate对Bean标签的解析,解析得到id和name这些信息封装到BeanDefinitionHolder并返回。
/*** BeanDefinitionParseDelegate**/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {return parseBeanDefinitionElement(ele, null);
}
/*** BeanDefinitionParseDelegate**/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {// 解析id属性String id = ele.getAttribute(ID_ATTRIBUTE);// 解析name属性String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);List<String> aliases = new ArrayList<>();if (StringUtils.hasLength(nameAttr)) {String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);aliases.addAll(Arrays.asList(nameArr));}String beanName = id;if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {beanName = aliases.remove(0);}if (containingBean == null) {checkNameUniqueness(beanName, aliases, ele);}AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);if (beanDefinition != null) {...String[] aliasesArray = StringUtils.toStringArray(aliases);return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);}
}
4.2 decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd)
功能概述: 4.1是对默认标签的属性解析,那如果标签有自定义属性和自定义子节点,这时就要通过
decorateBeanDefinitionIfRequired解析这些自定义属性和自定义子节点。
/*** BeanDefinitionParseDelegate**/
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {BeanDefinitionHolder finalDefinition = originalDef;// Decorate based on custom attributes first.// 首先对自定义属性解析和装饰NamedNodeMap attributes = ele.getAttributes();for (int i = 0; i < attributes.getLength(); i++) {Node node = attributes.item(i);finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);}// Decorate based on custom nested elements.// 装饰标签下的自定义子节点NodeList children = ele.getChildNodes();for (int i = 0; i < children.getLength(); i++) {Node node = children.item(i);if (node.getNodeType() == Node.ELEMENT_NODE) {finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);}}return finalDefinition;
}
5.1 registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
功能概述: 通过beanName注册BeanDefinition至BeanDefinitionMap中去,至此完成Bean标签的解析,转换成Bean在容器中的数据结构BeanDefinition.
/*** BeanDefinitionReaderUtils**/
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// Register bean definition under primary name.// 使用beanName注册BeanDefinitionString beanName = definitionHolder.getBeanName();registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// Register aliases for bean name, if any.// 使用别名注册BeanDefiniionString[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}
}/*** BeanDefinitionParseDelegate**/
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {...BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {...this.beanDefinitionMap.put(beanName, beanDefinition);}else{if (hasBeanCreationStarted()) {// beanDefinitionMap是全局变量,会存在并发访问问题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 phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}...
}
五. 结语
总结Spring IOC基础容器XmlBeanFactory的启动流程概括如下:
- 执行XmlFactoryBean构造方法,执行加载BeanDefinition方法。
- 使用XmlBeanDefinitionReader读取器将资源Resource解析成DOM Document对象。
- 使用DefaultBeanDefinitionDocumentReader读取器从Document对象解析出 Element。
- 通过BeanDefinitionParserDelegate将Element转换成对应的BeanDefinition。
- 实现BeanDefinitionRegistry注册器将解析好的BeanDefinition注册到容器中的BeanDefitionMap里去
本篇就XmlBeanFactory容器启动流程分析和源码解析两个角度来对Spring IOC容器有个基础的认识。有了这篇基础,下篇就开始对Spring的扩展容器ApplicationContext进行分析。最后希望大家看完都有所收获,感兴趣的朋友记得关注哦~
相关文章:

安装多个gcc
删除gcc #yum remove gcc 安装最新的 #yum install gcc 查找gcc源 可先通过“yum list compat-gcc*”查看版本,然后再利用“yum install compat-gccXXX”安装 #yum list compat-gcc* #sudo yum install compat-gcc-34.i686 查看gcc版本 #gcc -v #gcc34 -v参考&…

JAVA - HashMap和HashTable
1. HashMap 1) hashmap的数据结构 Hashmap本质就是一个数组,只是当key值重复时,使用链表的方式来存储重复的key值(拉链法),注意:链表中存放的仍然是key值。如下图示: 当我们往hashmap中put元素…

empress和queen区别_queen与empress
(1)「queen」和「empress」不仅可以用来指称「king」和「emperor」的妻子,也能指代握有正式权力的女性君主。(2) 英国的君主(queen或king)之所以曾经有过empress或emperor的头衔,是因为英国曾统治过印度次大陆, 他们曾是印度的empress或emperor。如今&am…

在UIWindow上加类似于“回到顶部”的按钮
在公司上个版本的开发中遇到了一个UI布局的小问题: 某个页面需要增加一个分享按钮,但是该页面是二级页面,导航栏右边也已经放置了2个button。 起初和老大谈论这个问题的时候想到的方法是导航栏右边加三个button得了~但是一回想,这…

修改mysql 默认字符集 , 默认引擎
cd /var/lib/mysql/gamell vim db.optdefault-character-setutf8default-collationutf8_general_ciwq service mysqld restart或者service mysqld reload默认字符集修改完毕vim /etc/my.cnf[mysqld]datadir/var/lib/mysqlsocket/var/lib/mysql/mysql.sockusermysqldefault-stor…

bzoj2724: [Violet 6]蒲公英(分块)
传送门 md调了一个晚上最后发现竟然是空间开小了……明明算出来够的…… 讲真其实我以前不太瞧得起分块,觉得这种基于暴力的数据结构一点美感都没有。然而今天做了这道分块的题才发现分块的暴力之美(如果我空间没有开小就更美了) 我们先将整个…

Linux0.01内核根目录Makefile注释
# # Makefile for linux. # If you dont have -mstring-insns in your gcc (and nobody but me has :-) # remove them from the CFLAGS defines. ## #8086汇编编译器和连接器. -0生成8086目标程序;-a生成与gas和gld部分兼容的代码 # AS86 as -0 -a CC86 cc -0 LD86 ld -0# #G…

快速滚动_方老师教滚动快速作文
五年级第一单元作文集阴沉天空中有一小束照着你的阳光。亲爱的孩子,让时间在知识的枝条上、智慧的绿叶上、成熟的果实上留下它勤奋的印痕!罗婉汀作文集自律且努力,别让生活太安逸。亲爱的孩子,耕耘者最信得过自己的汗水࿰…

liunx复制备份命令,copy命令,liunx命令
2019独角兽企业重金招聘Python工程师标准>>> 拷贝到的文件夹 /usr/local/文件夹/需要拷贝的路径文件夹 /usr/local/tomcat/webapps/文件夹/复制命令cp -r /usr/local/文件夹/ /usr/local/tomcat/webapps/文件夹/ 转载于:https://my.oschina.net/u/2336787/blog/635…

20.Valid Parentheses (python)
这道题主要用栈来实现的。什么是栈呢,参照书上的后缀表达式的例子谈谈自己的理解,栈最明显的特征是先进后出。所以可以有效的结合题目中 ()对匹配问题,可以把从列表中获取的符号先存到栈中。 首先建个空列表用于映射栈…

The HipHop Virtual Machine
目前Facebook已将该HipHop虚拟机开源,源代码发布在GitHub上。关于该工具的技术原理在Facebook的开发者页面上有一篇详细的文章介绍,查看这里。如果看不到的可以看下面的转载:Were always looking for ways to make our computing infrastruct…

node建立博客系统遇到的问题,1,乱码。2,multer的使用错误。3使用session问题...
2019独角兽企业重金招聘Python工程师标准>>> 1,乱码 文件存储为utf-8格式后还是报错。 原来这个设置只对新建文件编码有效,旧文件不处理的,我还以为旧文件也给转换了。 2,上传文件的multer模块使用错误。 throw new Ty…

python时间函数入门_calendar在python3时间中有哪些常用函数?怎么用?
想要在python中写代码游刃有余,没有函数的支持是万万不行的。很多小伙伴反映,最近函数的应用知识不够了,所以小编挑选了python3时间中的函数,希望可以帮助大家在处理日历方面更加的迅速。其他更多的函数,大家也可以自行…

9.spark core之共享变量
简介 spark执行操作时,可以使用驱动器程序Driver中定义的变量,但有时这种默认的使用方式却并不理想。 集群中运行的每个任务都会连接驱动器获取变量。如果获取的变量比较大,执行效率会非常低下。每个任务都会得到这些变量的一份新的副本&…

【CSDN2012年度博客之星】需要您的一票,感谢大家的支持
从2004年9月,本人一直将自己工作和学习经验写成博文分享给大家,本人有幸被选为2012年88位候选博客之星,如果各位IT‘er喜欢我的博文,请投我一票,做…

双绞线和同轴电缆
线缆作为连接器件,相当于不同系统之间沟通的“桥梁”,选择线缆类型的好坏,也决定着传输信号的质量,影响着整个系统的稳定性。 (1)特性阻抗 先说一下关于线缆在传输过程中的特性阻抗问题。 特性阻抗是指电缆…

keras训练完以后怎么预测_使用Keras建立Wide Deep神经网络,通过描述预测葡萄酒价格...
你能通过“优雅的单宁香”、“成熟的黑醋栗香气”或“浓郁的酒香”这样的描述,预测葡萄酒的价格吗?事实证明,机器学习模型可以。在这篇文章中,我将解释我是如何利用Keras(tf.keras)建立一个Wide & Deep神经网络,并…
如何发布自己的NPM包(模块)?
1.注册NPM 账号 注册地址:https://www.npmjs.com/。 2.初始化自己要发布的项目 搭建本地环境:安装node.js,包含了npm命令。新建目录,在该目录下,初始化项目:npm init。按照提示填写初始化信息,我…

PHP对于浮点型的数据需要用不同的方法去解决
Php: BCMathbc是Binary Calculator的缩写。bc*函数的参数都是操作数加上一个可选的 [int scale],比如string bcadd(string $left_operand, string $right_operand[, int $scale]),如果scale没有提供,就用bcscale的缺省值。这里大数直接用一个…

mysql提示符详解_MySQL字符集使用详解
查看字符集相关变量mysql> show variables like character%;————————–——————————-| Variable_name | Value |————————–——————————-| character_set_client | latin1 || character_set_connection | latin1 || character_set_database…

Apache漏洞修复
今天受同事的委托,修复一台服务器的Apache漏洞,主要集中在以下几点: 1.Apache httpd remote denial of service(中危) 修复建议:将Apache HTTP Sever升级到2.2.20或更高版本。 解决方法:升级HTT…

Java遍历Map对象的四种方式
关于java中遍历map具体哪四种方式,请看下文详解吧。 方式一 这是最常见的并且在大多数情况下也是最可取的遍历方式。在键值都需要时使用。 1 2 3 4 Map<Integer, Integer> map new HashMap<Integer, Integer>(); for (Map.Entry<Integer, Intege…

Tokyo Cabinet 安装
tokyocabinet :一个key-value的DBM数据库,但是没有提供网络接口,以下称TC。 tokyotyrant :是为TC写的网络接口,他支持memcache协议,也可以通过HTTP操作,以下称TT。 Tokyo Cabinet 是一款 DBM 数据库,Tokyo …

Packagist / Composer 中国全量镜像
Packagist 镜像 请各位使用本镜像的同学注意: 本镜像已经依照 composer 官方的数据源安全策略完全升级并支持 https 协议!请各位同学 按照下面所示的两个方法将 http://packagist.phpcomposer.com 修改为 https://packagist.phpcomposer.com 还没安装 co…
centos yum mysql-devel 5.5_CentOS 6.5下yum安装 MySQL-5.5全过程图文教程
在linux安装mysql是一个困难的事情,yum安装一般是安装的mysql5.1,现在经过自己不懈努力终于能用yum安装mysql5.5了。下面通过两种方法给大家介绍CentOS 6.5下yum安装 MySQL-5.5全过程,一起学习吧。方法一:具体方法和步骤如下所示&…

py 的 第 31 天
1.osi 7层模型 5层: 应用层 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 4层: 应用层 应用层 表示层 会话层 传输层 网络层 物理层 数据链路层 物理层 注意:7层背会。 2.tcp的三次握手&…

mysql实训报告_mysql数据库技术》实验报告.doc
mysql数据库技术》实验报告MySQL数据库技术实验报告系 别班 级学 号姓 名地点地点机房课程名称MySQL数据库技术实验名称实验1 MySQL的使用实 验 过 程目的要求:(1)掌握MySQL服务器安装方法(2)掌握MySQL Administrator的基本使用方法(3)基本了解数据库及其对象实验准…

PHP中魔术方法的用法
PHP中魔术方法的用法 /** PHP把所有以__(两个下划线)开头的类方法当成魔术方法。所以你定义自己的类方法时,不要以 __为前缀。 * */// __toString、__set、__get__isset()、__unset() /*The __toString method allows a class to decide how …

“互联网+”的时代,易佳互联也随着时代步伐前进着
一谈到互联网,我想大家的心里都不陌生,咱们总理工作报告中提出,制定“互联网”行动计划,推动移动互联网、云计算、大数据、物联网等与现代制造业结合,促进电子商务、工业互联网和互联网金融健康发展,引导互…

PHP 获取数组最后一个值
<?PHP$array array(1,2,4,6,8);echo end($array);?> <?PHP$array array(1,2,4,6,8);echo array_pop($array);?> <?PHP$array array(1,2,4,6,8);$k array_slice($array,-1,1);print_r($k); //结果是一维数组?>