我们到底能走多远系列(31)

扯淡:

  有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的。未婚的你们,你们是怎么分配工资的?

  毕竟,对自己的收入的分配差不多体现了自己的现状,以及自己对自己未来有什么样的期许~

  

主题:

  本人在阅读源码基本参考了《Spring技术内幕:深入解析 Spring架构与设计原理》,很不错的书籍,建议大家阅读。

  初始化IoC容器:1,resource定位  2,BeanDefinition载入  3,把BeanDefinition载入到IoC

重要的解释:

  Spring中的IoC容器,所谓的容器核心就是个hashMap,准确的说是ConcurrentHashMap,键值对就是:<String, BeanDefinition> key是bean的name。

  那么BeanDefinition就是对外界bean描述的抽象,比如你写的<bean>标签,最会被抽象成一个BeanDefinition放进这个Map中去。

  所以一个完整的IoC容器来说,只要提供对这个Map的必要操作就可以了。一般DefaultListableBeanFactory 作为一个默认功能完整的IoC容器来使用。

  上面的解释已经很清楚了,IoC容器的初始化就可以理解成,我们有个xml描述了一些bean的属性,Spring把它读进来,按照自己的规则解析一边,把其中的Bean描述转换成一个个BeanDefinition放进Map中去就完成初始化了。

  拿FileSystemXmlApplicationContext为例子看一下源码中是如何实现的:(希望有兴趣的先看下Spring中BeanFactory下面的继承结构)

  我们会写类似下面的代码开始我们的Spring之旅:

ApplicationContext ct = new FileSystemXmlApplicationContext("src/service/service.xml");


FileSystemXmlApplicationContext
的构造函数:

public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException { super(parent);
setConfigLocations(configLocations);
if (refresh) {
// 起点
refresh();
}
}

调用的refresh()方法是AbstractApplicationContext的方法:(这个方法就像执行顺序图,描述好了先做什么,后做什么)

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory. 这个步骤完成加载bean
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
}
}
}

obtainFreshBeanFactory()方法:

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
     // 这个方法是在AbstractApplicationContext定义没有实现的abstract方法,这就是所谓的模板模式吧,后面很多地方这样实现的,可以学习下。
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}   protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

refreshBeanFactory()方法是谁实现的呢?子类去实现。AbstractRefreshableApplicationContext实现的:

    protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
       // 这里我们就看到了,通过这个方法调用来初始化的,都使用了DefaultListableBeanFactory作为IoC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
       // 这个方法就去完成load Bean啦,不过它也使用了子类的实现
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

AbstractXmlApplicationContext实现的loadBeanDefinitions(DefaultListableBeanFactory beanFactory):

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
     // 更深一层后,这里就开始定义了Reader是什么了。我们要读取的xml文件,这个Reader可以帮助我们
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
     // 调用下面的的方法
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
       // 把工作交给XmlBeanDefinitionReader完成
reader.loadBeanDefinitions(configLocations);
}
}

通过XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader的方法把String configLocations封装成Recource,然后调用XmlBeanDefinitionReader实现的loadBeanDefinitions(resource)方法。

下面是父类的调用方法:

    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
     // 这里的for就可以理解多个xml文件的情况了
     // 从外面看,一个bean首先是放在多个xml中的一个,然后是一个xml文件中的多个bean描述中的一个,这个也是定位到一个bean要走的路。
for (Resource resource : resources) {
       // 交给子类实现
counter += loadBeanDefinitions(resource);
}
return counter;
}
子类实现:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
} Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
       // 用流的方式来读取,有点样子了哦~
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
         // 只是一个封装类,里面有属性防这个流而已
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
         // 我觉得到这里,看方法名就知道了,要开始do了,前面好像都没do嘛
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();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
       // 先解析成Document
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
       // 按照Spring的规则开始解析,放进BeanDefinition
return registerBeanDefinitions(doc, resource);
}
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);
}
}

XmlBeanDefinitionReader的registerBeanDefinitions方法:

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

上面代码可以看到:继续交给DefaultBeanDefinitionDocumentReader来解析Document:

下面是详细的处理过程:

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext; logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "environment property must not be null");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
} // 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 = createHelper(readerContext, root, parent); preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root); this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
       // 前面的注释中提到过bean定位时要从多个bean描述中一个个取,这个for循环就是了,
       //所以这个否循环里面的逻辑就是处理一个个bean的映射的,当然也有其他的标签,这里我们且认为只有bean吧
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);
}
}


parseDefaultElement方法:

    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)) {
// recurse ==>注意这个beans就递归,有调用了前面的doRegisterBeanDefinitions方法
doRegisterBeanDefinitions(ele);
}
}

processBeanDefinition方法:

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
     // 这里就出现了BeanDefinitionHolde 它封装了BeanDefinition
    // BeanDefinitionParserDelegate 来完成最底层的按照spring的规则解析
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));
}
}
parseBeanDefinitionElement方法的代码:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>();
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 (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
} if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
} AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
} return null;
}

上面解析的代码中有调用的一个方法parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)带我们去解析bean中更加详细的属性:

public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {// class属性
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
} try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {// parent属性
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
       // 下面parse方法解析其他的属性
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele)); return bd;
}
     // 下面的错误用spring有时候有看见过吧
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
} return null;
}

以上就是解析好了,然后就是放进传说中的IoC容器里啦:

BeanDefinitionReaderUtils的registerBeanDefinition方法:

    public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException { // Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
    // 调用了下BeanDefinitionRegistry 的方法,
    // 而这个registry就是DefaultListableBeanFactory,所有的BeanDefinition都要注册到它里面去呀...
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}

DefaultListableBeanFactory的registerBeanDefinition:

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 {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
synchronized (this.beanDefinitionMap) {
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
       // 保证加载bean唯一性
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
       // 放到前面提到的ConcurrentHashMap里面去喽~
this.beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName);
}
}

以上就是初始化IoC容器的过程。各位有兴趣可以自己debug进去一步步看既可以了。

另外用maven的话直接用下面命令下载源码即可:

mvn dependency:sources

让我们继续前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不会成功。
共勉。

初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)的更多相关文章

  1. cglib源码主流程源码-我们到底能走多远系列48

    扯淡 祝各位在园里的朋友新年快乐! 辛苦一年,为更好的自己也为更好的世界,很多人要感谢你们,你们也应该有很多人要感谢吧. 看了马斯克的采访视频,又想起兰迪·鲍许的最后一课,时光迁移,唯有梦想可坚持. ...

  2. 初始化IoC容器(Spring源码阅读)

    初始化IoC容器(Spring源码阅读) 我们到底能走多远系列(31) 扯淡: 有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的.未婚的你们,你们是怎么分配工资的? ...

  3. Spring源码阅读笔记02:IOC基本概念

    上篇文章中我们介绍了准备Spring源码阅读环境的两种姿势,接下来,我们就要开始探寻这个著名框架背后的原理.Spring提供的最基本最底层的功能是bean容器,这其实是对IoC思想的应用,在学习Spr ...

  4. Bean实例化(Spring源码阅读)-我们到底能走多远系列(33)

    我们到底能走多远系列(33) 扯淡: 各位:    命运就算颠沛流离   命运就算曲折离奇   命运就算恐吓着你做人没趣味   别流泪 心酸 更不应舍弃   ... 主题: Spring源码阅读还在继 ...

  5. Spring源码阅读-ApplicationContext体系结构分析

    目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...

  6. Spring源码阅读 之 配置的读取,解析

    在上文中我们已经知道了Spring如何从我们给定的位置加载到配置文件,并将文件包装成一个Resource对象.这篇文章我们将要探讨的就是,如何从这个Resouce对象中加载到我们的容器?加载到容器后又 ...

  7. Sping学习笔记(一)----Spring源码阅读环境的搭建

    idea搭建spring源码阅读环境 安装gradle Github下载Spring源码 新建学习spring源码的项目 idea搭建spring源码阅读环境 安装gradle 在官网中下载gradl ...

  8. 搭建 Spring 源码阅读环境

    前言 有一个Spring源码阅读环境是学习Spring的基础.笔者借鉴了网上很多搭建环境的方法,也尝试了很多,接下来总结两种个人认为比较简便实用的方法.读者可根据自己的需要自行选择. 方法一:搭建基础 ...

  9. Spring mvc源码url路由-我们到底能走多远系列(38)

    我们到底能走多远系列38 扯淡: 马航的事,挺震惊的.还是多多珍惜身边的人吧. 主题: Spring mvc 作为表现层的框架,整个流程是比较好理解的,毕竟我们做web开发的,最早也经常接触的就是一个 ...

随机推荐

  1. sql2008 附加数据库出错解决方法

    当遇到 无法为此请求检索数据,(Microsoft.SqlServer.SmoEnum)其他信息执行Transact-Sql语句或批处理时发生了异常, Microsoft.SqlServer.Conn ...

  2. qt 提高ui响应度

    如何使Qt 平台中的GUI保持响应流畅?一般来说耗时较长的操作,分为计算密集型操作和IO密集型操作,对于这两类操作如何提高响应速度. 而从操作的本质上来说,操作又可分为不可分解操作,如在第三方库中耗时 ...

  3. 使用ContentProvider管理联系人------搜索联系人

    此博客只实现了查询功能: import java.util.ArrayList; import android.os.Bundle;import android.provider.ContactsCo ...

  4. CentOS Hadoop格式化HDFS异常java.net.UnknownHostException

    #bin/hadoop namenode -format DEPRECATED: Use of this script to execute hdfs command is deprecated. I ...

  5. Unity3d之MonoBehaviour的可重写函数整理

    最近在学习Unity3d的知识.虽然有很多资料都有记录了,可是我为了以后自己复习的时候方便就记录下来吧!下面的这些函数在Unity3d程序开发中具有很重要的作用. Update 当MonoBehavi ...

  6. java jar

    http://www.cnblogs.com/shirui/p/5270969.html Java之 将程序打包成jar包   准备材料: 1.java文件: Helloworld.java pack ...

  7. Python中通过多个字符分割(split)字符串的方法

    python中字符串自带的split方法一次只能使用一个字符对字符串进行分割,但是python的正则模块则可以实现多个字符分割 import re re.split('-|_','sharejs_ha ...

  8. 从python中copy与deepcopy的区别看python引用

    讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用.python的内存管理. python中的一切事物皆为对象,并且规定参数的传递都是对象的引用.可能这样说听起来比较难懂,对比 ...

  9. long long 读数scanf的转换 #define

    在win32的评测系统下,long long scanf 要用"%I64d" ,而网上评测和考试要用"%lld",因此,难免有点麻烦,还会runtime err ...

  10. [VS]vs的宏

    宏的查看: 我们在Visual Studio中经常会接触到形如$(TargetFileName)这样的VS宏.它们不是全局宏,不能在一般CMD窗口中通过set命令查看, 但是可以通过VS的命令窗口打开 ...