首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

【Spring注解驱动开发】AOP核心类源码解析,这是最全的一篇了!!

点击上方蓝色“冰河技术”,关注并选择“设为星标” 持之以恒,贵在坚持,每天进步一点点! 作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址: https://github.com/sunshinelyz/mykit-delay PS: 欢迎各位Star源码,也可以pr你牛逼哄哄的代码。 写在前面 昨天二狗子让我给他讲@EnableAspectJAutoProxy注解,讲到AnnotationAwareAspectJAutoProxyCreator类的源码时,二狗子消化不了了。这不,今天又来让我给他讲讲AOP的核心类。那我们就开始吧! 关于 冰河技术 微信公众号,后台回复 “Spring注解”领取源码工程。 如果文章对你有点帮助,麻烦点个赞,给个在看和转发,大家的三连是对我持续创作最大的动力!! 类结构图 我们先来看下AnnotationAwareAspectJAutoProxyCreator类的结构图。 上图中一些 类/接口 的介绍: AspectJAwareAdvisorAutoProxyCreator : 公开了AspectJ的调用上下文,并弄清楚来自同一切面的多个Advisor在AspectJ中的优先级规则。 AbstractAdvisorAutoProxyCreator : 通用自动代理创建器,它基于检测到的每个顾问程序为特定bean构建AOP代理。 AbstractAutoProxyCreator : 扩展了 ProxyProcessorSupport,实现了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 接口,是BeanPostProcessor 实现,该实现使用AOP代理包装每个合格的bean,并在调用bean本身之前委派给指定的拦截器。 BeanFactoryAware : 实现了该接口的Bean可以知道它属于那个 BeanFactory,Bean可以通过Spring容器查找它的协同者(依赖查找),但大多数的Bean是通过构造器参数和Bean方法(依赖注入)来获取它的协同者。 BeanPostProcessor :工厂钩子,允许自定义修改新的bean实例。例如,检查标记接口或使用代理包装bean。如果我们需要在Spring容器中完成Bean的实例化,配置和其初始化前后添加一些自己的逻辑处理,我们就可以定义一个或多个BeanPostProcessor接口的实现,然后注册到容器中。 InstantiationAwareBeanPostProcessor : BeanPostProcessor 的子接口,它添加了实例化之前的回调,以及实例化之后但设置了显式属性或自动装配之前的回调。它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor 接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置。 SmartInstantiationAwareBeanPostProcessor : InstantiationAwareBeanPostProcessor 接口的扩展,多出了3个方法,添加了用于预测已处理bean的最终类型的回调,再加上父接口的5个方法,所以实现这个接口需要实现8个方法,主要作用也是在于目标对象的实例化过程中需要处理的事情。 总之: AspectJAwareAdvisorAutoProxyCreator为 AspectJ 切面类创建自动代理。 核心类解析 BeanPostProcessor 接口中的两个方法 postProcessBeforeInitialization 和 postProcessAfterInitialization,作用是对Bean初始化前后添加一些自己的逻辑。 @NullabledefaultObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;}@NullabledefaultObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;} InstantiationAwareBeanPostProcessor 是 BeanPostProcessor 的子接口,它额外增加了3个新的方法:postProcessBeforeInstantiation( 目标对象被实例化之前调用的方法,可以返回目标实例的一个代理用来代替目标实例 )、postProcessAfterInstantiation(该方法在Bean实例化之后执行,返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值) 和 postProcessPropertyValues(对属性值进行修改,未来版本将会删除) @NullabledefaultObjectpostProcessBeforeInstantiation(Class<?>beanClass,StringbeanName)throwsBeansException{returnnull;}defaultbooleanpostProcessAfterInstantiation(Objectbean,StringbeanName)throwsBeansException{returntrue;}@NullabledefaultPropertyValuespostProcessPropertyValues(PropertyValuespvs,PropertyDescriptor[]pds,Objectbean,StringbeanName)throwsBeansException{returnpvs;} SmartInstantiationAwareBeanPostProcessor接口继承InstantiationAwareBeanPostProcessor接口,里面定义了3个方法:predictBeanType(预测Bean的类型)、determineCandidateConstructors(选择合适的构造器)、getEarlyBeanReference(解决循环引用问题)。 @NullabledefaultClass<?>predictBeanType(Class<?>beanClass,StringbeanName)throwsBeansException{returnnull;}@NullabledefaultConstructor<?>[]determineCandidateConstructors(Class<?>beanClass,StringbeanName)throwsBeansException{returnnull;}defaultObjectgetEarlyBeanReference(Objectbean,StringbeanName)throwsBeansException{returnbean;} AbstractAutoProxyCreator 是AOP的一个核心类,它实现了SmartInstantiationAwareBeanPostProcessor、BeanFactoryAware 接口,实现了代理创建的逻辑,使用AOP代理包装每个合格的bean,并在调用bean本身之前委派给指定的拦截器。 AbstractAdvisorAutoProxyCreator 通用自动代理创建器,它基于检测每个bean的增强器,为特殊的bean构建AOP代理。子类可以重写此findCandidateAdvisors()方法,以返回适用于任何对象的advisor的自定义列表,子类还可以重写继承的AbstractAutoProxyCreator.shouldSkip()方法,以将某些对象排除在自动代理之外。 protectedList<Advisor>findCandidateAdvisors(){Assert.state(this.advisorRetrievalHelper!=null,"NoBeanFactoryAdvisorRetrievalHelperavailable");returnthis.advisorRetrievalHelper.findAdvisorBeans();} AspectJAwareAdvisorAutoProxyCreator 扩展 AbstractAdvisorAutoProxyCreator,公开了AspectJ的调用上下文,并在多个增强器来自同一切面时搞清楚AspectJ的建议优先级顺序。按AspectJ优先级排序其余部分: @Override@SuppressWarnings("unchecked")protectedList<Advisor>sortAdvisors(List<Advisor>advisors){List<PartiallyComparableAdvisorHolder>partiallyComparableAdvisors=newArrayList<>(advisors.size());for(Advisorelement:advisors){partiallyComparableAdvisors.add(newPartiallyComparableAdvisorHolder(element,DEFAULT_PRECEDENCE_COMPARATOR));}List<PartiallyComparableAdvisorHolder>sorted=PartialOrder.sort(partiallyComparableAdvisors);if(sorted!=null){List<Advisor>result=newArrayList<>(advisors.size());for(PartiallyComparableAdvisorHolderpcAdvisor:sorted){result.add(pcAdvisor.getAdvisor());}returnresult;}else{returnsuper.sortAdvisors(advisors);}} 在增强链头部增加一个ExposeInvocationInterceptor,使用AspectJ表达式切入点和使用AspectJ样式的advisor时,需要这些附加advisor。 protectedvoidextendAdvisors(List<Advisor>candidateAdvisors){AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);} 如果此后处理器不应该考虑将给定的bean用于自动代理,子类应重写此方法以返回true @OverrideprotectedbooleanshouldSkip(Class<?>beanClass,StringbeanName){//TODO:ConsideroptimizationbycachingthelistoftheaspectnamesList<Advisor>candidateAdvisors=findCandidateAdvisors();for(Advisoradvisor:candidateAdvisors){if(advisorinstanceofAspectJPointcutAdvisor&&((AspectJPointcutAdvisor)advisor).getAspectName().equals(beanName)){returntrue;}}returnsuper.shouldSkip(beanClass,beanName);} AspectJAwareAdvisorAutoProxyCreator 还有一个子类叫 AnnotationAwareAspectJAutoProxyCreator,子类AnnotationAwareAspectJAutoProxyCreator是用于处理当前应用程序上下文中的所有AspectJ注释方面以及Spring Advisor。如果Spring AOP的基于代理的模型能够应用任何AspectJ注释的类,它们的advisor将被自动识别,这涵盖了方法执行连接点,Spring Advisor的处理遵循AbstractAdvisorAutoProxyCreator中建立的规则。 生成代理对象 从使用aop:xxx标签来自动生成代理的话,先看看AopNamespaceHandler,使用aop:config标签则使用 ConfigBeanDefinitionParser 解析,使用了aop:aspectj-autoproxy标签则使用 AspectJAutoProxyBeanDefinitionParser 解析,依次类推。 @Overridepublicvoidinit(){//In2.0XSDaswellasin2.1XSD.registerBeanDefinitionParser("config",newConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy",newAspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy",newScopedProxyBeanDefinitionDecorator());//Onlyin2.0XSD:movedtocontextnamespaceasof2.1registerBeanDefinitionParser("spring-configured",newSpringConfiguredBeanDefinitionParser());} aop:config方式使用 AspectJAwareAdvisorAutoProxyCreator 创建代理 aop:aspectj-autoproxy使用 AnnotationAwareAspectJAutoProxyCreator 创建代理 ConfigBeanDefinitionParser.java @Override@NullablepublicBeanDefinitionparse(Elementelement,ParserContextparserContext){CompositeComponentDefinitioncompositeDef=newCompositeComponentDefinition(element.getTagName(),parserContext.extractSource(element));parserContext.pushContainingComponent(compositeDef);configureAutoProxyCreator(parserContext,element);//注册AspectJAwareAdvisorAutoProxyCreatorList<Element>childElts=DomUtils.getChildElements(element);for(Elementelt:childElts){StringlocalName=parserContext.getDelegate().getLocalName(elt);if(POINTCUT.equals(localName)){parsePointcut(elt,parserContext);}elseif(ADVISOR.equals(localName)){parseAdvisor(elt,parserContext);}elseif(ASPECT.equals(localName)){parseAspect(elt,parserContext);}}parserContext.popAndRegisterContainingComponent();returnnull;}privatevoidconfigureAutoProxyCreator(ParserContextparserContext,Elementelement){AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext,element);} AopConfigUtils.java @Override@NullablepublicBeanDefinitionparse(Elementelement,ParserContextparserContext){CompositeComponentDefinitioncompositeDef=newCompositeComponentDefinition(element.getTagName(),parserContext.extractSource(element));parserContext.pushContainingComponent(compositeDef);configureAutoProxyCreator(parserContext,element);//注册AspectJAwareAdvisorAutoProxyCreatorList<Element>childElts=DomUtils.getChildElements(element);for(Elementelt:childElts){StringlocalName=parserContext.getDelegate().getLocalName(elt);if(POINTCUT.equals(localName)){parsePointcut(elt,parserContext);}elseif(ADVISOR.equals(localName)){parseAdvisor(elt,parserContext);}elseif(ASPECT.equals(localName)){parseAspect(elt,parserContext);}}parserContext.popAndRegisterContainingComponent();returnnull;}privatevoidconfigureAutoProxyCreator(ParserContextparserContext,Elementelement){AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext,element);} AopConfigUtils.java publicstaticvoidregisterAspectJAutoProxyCreatorIfNecessary(ParserContextparserContext,ElementsourceElement){//在这里注册的是AspectJAwareAdvisorAutoProxyCreatorBeanDefinitionbeanDefinition=AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext.getRegistry(),parserContext.extractSource(sourceElement));useClassProxyingIfNecessary(parserContext.getRegistry(),sourceElement);registerComponentIfNecessary(beanDefinition,parserContext);//注册组件} @NullablepublicstaticBeanDefinitionregisterAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistryregistry,@NullableObjectsource){returnregisterOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class,registry,source);} AspectJAwareAdvisorAutoProxyCreator 实现了 BeanPostProcessor 等上面介绍的接口,主要作用于Bean初始化前后,实例化前后,所有的Bean都被作用到。InstantiationAwareBeanPostProcessor 是 BeanPostProcessor的子接口,但它的调用时间点发生在Bean实例化前,在真正调用doCreateBean()创建bean实例之前执行postProcessBeforeInstantiation()。 AbstractAutoProxyCreator.java @OverridepublicObjectpostProcessBeforeInstantiation(Class<?>beanClass,StringbeanName)throwsBeansException{ObjectcacheKey=getCacheKey(beanClass,beanName);//得到一个缓存的唯一key(根据beanClass和beanName生成唯一key)//如果当前targetSourcedBeans(通过自定义TargetSourceCreator创建的TargetSource)不包含cacheKeyif(!StringUtils.hasLength(beanName)||!this.targetSourcedBeans.contains(beanName)){if(this.advisedBeans.containsKey(cacheKey)){//advisedBeans(已经被增强的Bean,即AOP代理对象)中包含当前cacheKey,返回null,即走Spring默认流程returnnull;}if(isInfrastructureClass(beanClass)||shouldSkip(beanClass,beanName)){//如果是基础设施类(如Advisor、Advice、AopInfrastructureBean的实现)不进行处理;(略)this.advisedBeans.put(cacheKey,Boolean.FALSE);returnnull;}}//如果有自定义的TargetSource,在此处创建代理//禁止目标Bean的不必要的默认实例化:// TargetSource将以自定义方式处理目标实例。TargetSourcetargetSource=getCustomTargetSource(beanClass,beanName);if(targetSource!=null){if(StringUtils.hasLength(beanName)){this.targetSourcedBeans.add(beanName);}Object[]specificInterceptors=getAdvicesAndAdvisorsForBean(beanClass,beanName,targetSource);Objectproxy=createProxy(beanClass,beanName,specificInterceptors,targetSource);this.proxyTypes.put(cacheKey,proxy.getClass());returnproxy;}returnnull;} 通过 AbstractAutoProxyCreator 中的 postProcessAfterInitialization() 创建AOP代理。 @OverridepublicObjectpostProcessAfterInitialization(@NullableObjectbean,StringbeanName)throwsBeansException{if(bean!=null){ObjectcacheKey=getCacheKey(bean.getClass(),beanName);if(!this.earlyProxyReferences.contains(cacheKey)){//如果之前调用过getEarlyBeanReference获取包装目标对象到AOP代理对象(如果需要),则不再执行returnwrapIfNecessary(bean,beanName,cacheKey);//包装目标对象到AOP代理对象(如果需要)}}returnbean;}protectedObjectwrapIfNecessary(Objectbean,StringbeanName,ObjectcacheKey){if(StringUtils.hasLength(beanName)&&this.targetSourcedBeans.contains(beanName)){//通过TargetSourceCreator进行自定义TargetSource不需要包装returnbean;}if(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))){//不应该被增强对象不需要包装returnbean;}if(isInfrastructureClass(bean.getClass())||shouldSkip(bean.getClass(),beanName)){//基础设施或应该skip的不需要保证this.advisedBeans.put(cacheKey,Boolean.FALSE);returnbean;}//如果有advise则创建代理。Object[]specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(),beanName,null);if(specificInterceptors!=DO_NOT_PROXY){this.advisedBeans.put(cacheKey,Boolean.TRUE);Objectproxy=createProxy(bean.getClass(),beanName,specificInterceptors,newSingletonTargetSource(bean));//创建代理对象this.proxyTypes.put(cacheKey,proxy.getClass());returnproxy;}this.advisedBeans.put(cacheKey,Boolean.FALSE);returnbean;} 重磅福利 关注「 冰河技术 」微信公众号,后台回复 “设计模式” 关键字领取《深入浅出Java 23种设计模式》PDF文档。回复“Java8”关键字领取《Java8新特性教程》PDF文档。回复“限流”关键字获取《亿级流量下的分布式限流解决方案》PDF文档,三本PDF均是由冰河原创并整理的超硬核教程,面试必备!! 好了,今天就聊到这儿吧!别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!! 写在最后 如果你觉得冰河写的还不错,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发、分布式、微服务、大数据、互联网和云原生技术,「 冰河技术 」微信公众号更新了大量技术专题,每一篇技术文章干货满满!不少读者已经通过阅读「 冰河技术 」微信公众号文章,吊打面试官,成功跳槽到大厂;也有不少读者实现了技术上的飞跃,成为公司的技术骨干!如果你也想像他们一样提升自己的能力,实现技术能力的飞跃,进大厂,升职加薪,那就关注「 冰河技术 」微信公众号吧,每天更新超硬核技术干货,让你对如何提升技术能力不再迷茫! 如果你喜欢这篇文章,欢迎点赞和转发。 生活很美好,明天见(。・ω・。)ノ♡ 写留言 本文分享自微信公众号 - 冰河技术(hacker-binghe)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Nebula Graph 在大规模数据量级下的实践和定制化开发

本文作者系微信技术专家李本利 图数据在社交推荐、多跳实时计算、风控和安全等领域有可期待的前景。如何用图数据库高效存储和查询大规模异构图数据,是一个重大挑战。本文描述了开源分布式图数据库 Nebula Graph 实践中遇到的问题,并通过深度定制,实现:大数据集存储、小时级全量导入、多版本控制、秒级回滚、毫秒级访问等特性。 背景 为大众所熟知的图数据库大多在大数据集合上束手无策,如:Neo4j 的社区版本,采用 Cypher语言,由单机单副本提供服务,广泛应用于图谱领域。互联网公司只能在小数据集合下使用,还要解决 Neo4j 多副本一致性容灾的问题。JanusGraph 虽然通过外置元数据管理、kv 存储和索引的方式解决了大数据集合存储问题,但其存在广为诟病的性能问题。我们看到大部分图数据库在对比性能时都会提到和 JanusGraph 相比有几十倍以上的性能提升。 面临大数据量挑战的互联网公司,普遍走向了自研之路,为了贴合业务需求,仅支持有限的查询语义。国内主流互联网公司如何解决图数据库的挑战呢: 蚂蚁金服:GeaBase[1] 金融级图数据库,通过自定义类语言为业务方提供服务,全量计算下推,提供毫秒级延时。主要应用于以下场景: 金融风控场景:万亿级边资金网络,存储实时交易信息,实时欺诈检测。 推荐场景:股票证券推荐。 蚂蚁森林:万亿级的图存储能力,低延时强一致关系数据查询更新。 GNN:用于小时级 GNN 训练。尝试动态图 GNN 在线推理。[7] 阿里巴巴:iGraph[2] iGraph 是图索引及查询系统,存储用户的行为信息,是阿里数据中台四驾马车之一。通过 Gremlin 语言为业务方提供电商图谱实时查询。 今日头条:ByteGraph[3] ByteGraph 通过在 kv 上增加统一 cache 层,关系数据拆分为 B+ 树以应对高效的边访问和采样,类似 Facebook 的 TAO [6]。 ... 架构图 实践 从哪里开始呢? 我们选择从 Nebula Graph[4] 开始我们的图数据库之旅,其吸引我们的有以下几点: 数据集分片,每条边独立存储,超大规模数据集存储潜力。 定制强一致存储引擎,具有计算下推和 MMP 优化的潜力。 创始团队有丰富的图数据库经验,大数据集合下模型抽象思路经过验证。 实践中的问题 内存爆炸 本质上这是一个性能 VS 资源的问题,数据规模庞大的应用中,内存占用是一个不容忽视的问题。RocksDB 内存由三部分构成:block cache、index 和 bloom filter、iter pined block。 block cache 优化:采用全局 LRU cache,控制机器上所有 rocksdb 实例的 cache 占用。 bloom filter 优化:一条边被设计为一个 kv 存入到 rocksdb,如果全部 key 保存 bloom filter,每个 key 占用 10bit 空间,那么整个 filter 内存占用远超机器内存。观察到我们大部分的请求模式是获取某一个点的边列表,因此采用 prefix bloom filter;索引到点属性这一层实际上即可以对大多数请求进行加速。经过这个优化,单机 filter 所占用内存在 G 这个级别,大多数请求访问速度并未明显降低。 多版本控制 实践中,图数据需要进行快速回滚,定期全量导入,自动访问最新版本数据。我们把数据源大致可以分为两种类型: 周期性数据:比如,按天计算相似用户列表,导入后数据生效。 历史数据+实时数据:比如,历史数据按天刷新,和实时写入的数据进行合并成为全量数据。 如下是数据在 rocksdb 的存储模型: vertex 存储格式 edge 存储格式 其中实时写入的数据 version 记录为时间戳。离线导入的数据 version 需要自己指定。我们将该字段和离线导入模块联合使用,用三个配置项进行版本控制:reserve_versions(需要保留的版本列表)、active_version(用户请求访问到的版本号)、max_version(保留某个版本之后数据,把历史数据和实时写入数据进行合并)。这样可以高效管理离线数据和在线数据,不再使用的数据在下一次 compaction 中被清除出磁盘。 通过这样的方式,业务代码可以无感更新数据版本,并做到了秒级回滚。 举例: 保留 3 个版本,激活其中一个版本: alter edge friend reserve_versions = 1 2 3 active_version = 1 数据源为历史数据+实时导入数据。 alter edge friend max_version = 1592147484 快速批量导入 实践中导入大量数据是常规操作,如果不经任何优化,将需要导入的数据转为请求发给图数据库,不仅严重影响线上请求,而且大数据量导入耗时超过一天。对导入速度进行优化迫在眉睫。业界解决这个问题一般采用 SST Ingest 方式[5]。我们也是采用类似方式,通过例行调度 spark 任务,离线生成磁盘文件。然后数据节点拉取自己所需要的数据,并 ingest 到数据库中,之后进行版本切换控制请求访问最新版本数据。 整个过程导入速度快,约数个小时内完成全部过程。计算过程主要离线完成,对图数据库请求影响小。 shared nothing 这是近年来老生常谈的并发加速方式,然而要落地还是考验工程师的编程功底。meta cache 访问频繁,并用 shared_ptr 进行封装,也就成为了原子操作碰撞的高发地。为了能够实现真正的 shared nothing,我们将每一份 meta cache 拷贝为 thread local,具体解决方案请参考该 pull request [8] 小结 图数据库路阻且长,且行且珍惜。如果对于本文有什么疑问,可以在 GitHub[9] 上找找。 参考文献 Fu, Zhisong, Zhengwei Wu, Houyi Li, Yize Li, Min Wu, Xiaojie Chen, Xiaomeng Ye, Benquan Yu, and Xi Hu. "GeaBase: a high-performance distributed graph database for industry-scale applications." International Journal of High Performance Computing and Networking 15, no. 1-2 (2019): 12-21. https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247489027&idx=3&sn=c149ce488cfc5231d4273d6da9dc8679&chksm=fbb29ffdccc516ebb8313b9202cfd78ea199da211c55b0a456a9e632a33e7d5b838d8da8bc6a&mpshare=1&scene=1&srcid=0614MWpeEsBc1RaBrl4htn3D&sharer_sharetime=1592106638907&sharer_shareid=a2497c4756f8bac1bcbef9edf86a86ac&rd2werd=1#wechat_redirect https://zhuanlan.zhihu.com/p/109401046 https://github.com/vesoft-inc/nebula https://www.infoq.cn/article/SPYkxplsq7f36L1QZIY7 Bronson, Nathan, Zach Amsden, George Cabrera, Prasad Chakka, Peter Dimov, Hui Ding, Jack Ferris et al. "{TAO}: Facebook’s distributed data store for the social graph." In Presented as part of the 2013 {USENIX} Annual Technical Conference ({USENIX}{ATC} 13), pp. 49-60. 2013. http://blog.itpub.net/69904796/viewspace-2653498/ https://github.com/vesoft-inc/nebula/pull/2165 https://github.com/xuguruogu/nebula 腾讯高性能分布式图计算框架柏拉图 https://github.com/Tencent/plato 🤩 加入 Nebula Graph 交流群,请联系 Nebula Graph 官方小助手微信号:NebulaGraphbot

优秀的个人博客,低调大师

Chrome开发者工具里的一个隐藏技能:chrome://net-internals

During my holiday I was writing a small tool for fun, which extracts my personal posts from http://www.baidu.com for further analysis.I am using AJAX in jQuery to perform a synchronous call to fetch html source code of given url specified by argument requestURL.、 function getPostByAJAX(requestURL){ var html = $.ajax({ url: requestURL, async: false}).responseText; return html; } The requestURL I am using is http://tieba.baidu.com/i/i/my_tie However when I try to access it via my JavaScript code above, it failed.And Chrome development tool didn’t give me enough information for trouble shooting. How to deal with this issue then? Then I found the useful tool from Google: chrome://net-internalsNow let’s continue to trouble shoot with this tool. (1) type chrome://net-internals in Chrome address bar, press enter key.Then click Event hyperlink. (2) Go to my own html page which will send AJAX request via jQuery, click F5 to send a new request, then go back to Chrome tool.Now I have found the trace entry for the sent request.Here below is the request detail which contains much more information compared with the one in Chrome development Tool-Network tab. And here below are response header fields: The return code 302 and location “http://static.tieba.baidu.com/tb/error.html?ErrType=1” give me a reminder that this issue might be related to logon state of BAIDU website, since I would like to return my personal information, it makes sense that the url can only return personal data if cookie is available or user credential is specified ( not supported by BAIDU in this case ).In order to verify my assumption, I request the url directly in Chrome and check its request header fields this time, and yes, the cookie field is there: So now the question is, how to send my cookie information together with the AJAX call in JavaScript code?I found this article from Google.According to the article, I add the following code in my function: And it works now: By the way, via this tool I can also figure out how the jQuery library file jquery1.7.1.js stored in local laptop is loaded by Chrome.Chrome reads this file by chunks with size 32768 ( the file consists of 8 chunks ). The total size 251661 matches exactly with the number I see in windows, perfect isn’t it? Further reading For more tips I gained during my daily work about Chrome development tools, please refer to this blog Chrome Development Tool tips used in my daily work. 本文来自云栖社区合作伙伴“汪子熙”,了解相关信息可以关注微信公众号"汪子熙"。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册