首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

HBase全网最佳学习资料汇总

前言 HBase这几年在国内使用的越来越广泛,在一定规模的企业中几乎是必备存储引擎,互联网企业阿里巴巴、京东、小米都有数千台的HBase集群,中国电信的话单、中国人寿的保单都是存储在HBase中。注意大公司有数十个数百个HBase集群,此点跟Hadoop集群很不相同。另外,数据需求,很多公司是mysql+hbase+hadoop(spark),满足关系型数据库需求,满足大规模结构化存储需求,满足复杂分析的需求。如此流行的原因来源于很多方面,如: 开源繁荣的生态:1. 任何公司倒闭了,开源的HBase还在 2.几乎每家公司都可以去下载源码,改进她,再反馈给社区,就如阿里已经反馈了数百个patch了。加入的人越多,引擎就越好 跟HADOOP深度结合:本就同根同源,在数据存储在HBase后,如果想复杂分析,则非常方便 高扩展、高容量、高性能、低

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

Spark学习之RDD简单算子

collect 返回RDD的所有元素 scala>varinput=sc.parallelize(Array(-1,0,1,2,2)) input:org.apache.spark.rdd.RDD[Int]=ParallelCollectionRDD[15]atparallelizeat<console>:27 scala>varresult=input.collect result:Array[Int]=Array(-1,0,1,2,2) count,coutByValue count返回RDD的元素数量,countByValue返回每个值的出现次数 scala>varinput=sc.parallelize(Array(-1,0,1,2,2)) scala>varresult=input.count result:Long=5 scala>varresult=input.countByValue result:scala.collection.Map[Int,Long]=Map(0->1,1->1,2->2,-1->1) take,top,takeOrdered take返回RDD的前N个元素 takeOrdered默认返回升序排序的前N个元素,可以指定排序算法 Top返回降序排序的前N个元素 varinput=sc.parallelize(Array(1,2,3,4,9,8,7,5,6)) scala>varresult=input.take(6) result:Array[Int]=Array(1,2,3,4,9,8) scala>varresult=input.take(20) result:Array[Int]=Array(1,2,3,4,9,8,7,5,6) scala>varresult=input.takeOrdered(6) result:Array[Int]=Array(1,2,3,4,5,6) scala>varresult=input.takeOrdered(6)(Ordering[Int].reverse) result:Array[Int]=Array(9,8,7,6,5,4) scala>varresult=input.top(6) result:Array[Int]=Array(9,8,7,6,5,4 ) Filter 传入返回值为boolean的函数,返回改函数结果为true的RDD scala>varinput=sc.parallelize(Array(-1,0,1,2)) scala>varresult=input.filter(_>0).collect() result:Array[Int]=Array(1,2) map,flatmap map对每个元素执行函数,转换为新的RDD,flatMap和map类似,但会把map的返回结果做flat处理,就是把多个Seq的结果拼接成一个Seq输出 scala>varinput=sc.parallelize(Array(-1,0,1,2)) scala>varresult=input.map(_+1).collect result:Array[Int]=Array(0,1,2,3) scala>varresult=input.map(x=>x.to(3)).collect result:Array[scala.collection.immutable.Range.Inclusive]=Array(Range(-1,0,1,2,3),Range(0,1,2,3),Range(1,2,3),Range(2,3)) scala>varresult=input.flatMap(x=>x.to(3)).collect result:Array[Int]=Array(-1,0,1,2,3,0,1,2,3,1,2,3,2,3) distinct RDD去重 scala>varinput=sc.parallelize(Array(-1,0,1,2,2)) scala>varresult=input.distinct.collect result:Array[Int]=Array(0,1,2,-1) Reduce 通过函数聚集RDD中的所有元素 scala>varinput=sc.parallelize(Array(-1,0,1,2)) scala>varresult=input.reduce((x,y)=>{println(x,y);x+y}) (-1,1)//处理-1,1,结果为0,RDD剩余元素为{0,2} (0,2)//上面的结果为0,在处理0,2,结果为2,RDD剩余元素为{0} (2,0)//上面结果为2,再处理(2,0),结果为2,RDD剩余元素为{} result:Int=2 sample,takeSample sample就是从RDD中抽样,第一个参数withReplacement是指是否有放回的抽样,true为放回,为false为不放回,放回就是抽样结果可能重复,第二个参数是fraction,0到1之间的小数,表明抽样的百分比 takeSample类似,但返回类型是Array,第一个参数是withReplacement,第二个参数是样本个数 varrdd=sc.parallelize(1to20) scala>rdd.sample(true,0.5).collect res33:Array[Int]=Array(6,8,13,15,17,17,17,18,20) scala>rdd.sample(false,0.5).collect res35:Array[Int]=Array(1,3,10,11,12,13,14,17,18) scala>rdd.sample(true,1).collect res44:Array[Int]=Array(2,2,3,5,6,6,8,9,9,10,10,10,14,15,16,17,17,18,19,19,20,20) scala>rdd.sample(false,1).collect res46:Array[Int]=Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) scala>rdd.takeSample(true,3) res1:Array[Int]=Array(1,15,19) scala>rdd.takeSample(false,3) res2:Array[Int]=Array(7,16,6) collectAsMap,countByKey,lookup collectAsMap把PairRDD转为Map,如果存在相同的key,后面的会覆盖前面的。 countByKey统计每个key出现的次数 Lookup返回给定key的所有value scala>varinput=sc.parallelize(List((1,"1"),(1,"one"),(2,"two"),(3,"three"),(4,"four"))) scala>varresult=input.collectAsMap result:scala.collection.Map[Int,String]=Map(2->two,4->four,1->one,3->three) scala>varresult=input.countByKey result:scala.collection.Map[Int,Long]=Map(1->2,2->1,3->1,4->1) scala>varresult=input.lookup(1) result:Seq[String]=WrappedArray(1,one) scala>varresult=input.lookup(2) result:Seq[String]=WrappedArray(two) groupBy,keyBy groupBy根据传入的函数产生的key,形成元素为K-V形式的RDD,然后对key相同的元素分组 keyBy对每个value,为它加上key scala>varrdd=sc.parallelize(List("A1","A2","B1","B2","C")) scala>varresult=rdd.groupBy(_.substring(0,1)).collect result:Array[(String,Iterable[String])]=Array((A,CompactBuffer(A1,A2)),(B,CompactBuffer(B1,B2)),(C,CompactBuffer(C))) scala>varrdd=sc.parallelize(List("hello","world","spark","is","fun")) scala>varresult=rdd.keyBy(_.length).collect result:Array[(Int,String)]=Array((5,hello),(5,world),(5,spark),(2,is),(3,fun)) keys,values scala>varinput=sc.parallelize(List((1,"1"),(1,"one"),(2,"two"),(3,"three"),(4,"four"))) scala>varresult=input.keys.collect result:Array[Int]=Array(1,1,2,3,4) scala>varresult=input.values.collect result:Array[String]=Array(1,one,two,three,four) mapvalues mapvalues对K-V形式的RDD的每个Value进行操作 scala>varinput=sc.parallelize(List((1,"1"),(1,"one"),(2,"two"),(3,"three"),(4,"four"))) scala>varresult=input.mapValues(_*2).collect result:Array[(Int,String)]=Array((1,11),(1,oneone),(2,twotwo),(3,threethree),(4,fourfour)) union,intersection,subtract,cartesian union合并2个集合,不去重 subtract将第一个集合中的同时存在于第二个集合的元素去掉 intersection返回2个集合的交集 cartesian返回2个集合的笛卡儿积 scala>varrdd1=sc.parallelize(Array(-1,1,1,2,3)) scala>varrdd2=sc.parallelize(Array(0,1,2,3,4)) scala>varresult=rdd1.union(rdd2).collect result:Array[Int]=Array(-1,1,1,2,3,0,1,2,3,4) scala>varresult=rdd1.intersection(rdd2).collect result:Array[Int]=Array(1,2,3) scala>varresult=rdd1.subtract(rdd2).collect result:Array[Int]=Array(-1) scala>varresult=rdd1.cartesian(rdd2).collect result:Array[(Int,Int)]=Array((-1,0),(-1,1),(-1,2),(-1,3),(-1,4),(1,0),(1,1),(1,2),(1,3),(1,4),(1,0),(1,1),(1,2),(1,3),(1,4),(2,0),(2,1),(2,2),(2,3),(2,4),(3,0),(3,1),(3,2),(3,3),(3,4)) 本文作者:Endless2010 来源:51CTO

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

Android中Service深入学习

概述 1、当用户在与当前应用程序不同的应用程序时,Service可以继续在后台运行。 2、Service可以让其他组件绑定,以便和它交互并进行进程间通信。 3、Service默认运行在创建它的应用程序的主线程中。 Service的使用主要是因为应用程序里面可能需要长时间地运行一些任务但是又不需要用户界面或者应用程序本身需要对外提供一些函数给其他的应用程序调用。每一个Service实体类必须相应地在它的包中的AndroidManifest.xml有一个<service>配置节的声明。Services可以用Context.startService()或Context.bindService()来启动。 下面我们将会涉及到几个主题: 1、什么是Service? 2、Service的生命周期 3、进程生命周期 什么是Service? 很多Android的初学者都对Service抱有浓浓的疑惑,Service到底是什么,但是似乎更多的问题是Service到底不是什么? Service不是一个独立的进程。Service不像他的名字所暗示的,它没有自己独立的进程;除非另外指定,Service运行在跟应用程序相同的进程中,并且他是应用程序进程的一部分。 Service不是一个线程。但也不是说Service就运行在界面主线程(Main Thread)中( Android中为了避免应用程序没有响应的错误)。 其实Service非常简单,它主要有两个特性: 它是一种应用程序跟系统进行沟通的机制,告诉系统有一些任务要在后台运行(即在用户使用应用程序的时候)。我们可以对应地调用Context.startService()让系统运行Service,Service会一直运行,直到Service本身或者其他人显式地停止它。 它是一个应用程序对外(其他应用程序)暴露函数接口的机制。我们可以对应地调用Context.bindService()来运行,这样子其他的应用程序就可以长时间地跟Service连接,进行一些交互。 在一个Service组件被创建的时候,系统做的工作其实就是在主线程上实例化Service组件,然后调用Service的onCreate()还有其他Service的回调函数而已。也就是说,可以认为系统除了调用一下Service的函数,其他什么都不会再做了,如果你想要运行什么长时间的任务,比如从网络上下载文件,那么跟以前一样,你需要自己写一个线程,当然是在Service内对应的函数中。 不过正因为Service本身如此简单,我们可以自由定义Service,使之与外界进行一些简单或者复杂的交互。我们可以将Service视为本地Java对象,进行直接的方法调用(具体的示例见Local Service Sample),也可以通过AIDL提供一个完全的远程接口。 Service的生命周期 Service是由Android系统进行调度的。如果有人调用Context.startService(),系统就会将Service取回(有必要的时候创建它,并调用它的onCreate()方法)然后调用它的onStartCommand(Intent, int, int)方法,使用客户端提供的参数。这时候,Service会继续运行运行直到Context.stopService()orstopSelf()被调用。注意:我们可以多次调用Context.startService()不会发送嵌套调用(尽管会有多次onStartCommand()的响应),所以不管Service多少次被启动,它都只会在一次Context.stopService() 或stopSelf()的调用中被停止。然而,service可以使用它的stopSelf(int)方法来保证自己不会被停止,直到启动它的intents被处理完。 对于一个启动的服务(started Service)有两种操作模型,这决定了它们不同的运行方式,而运行方式由它们的OnStartCommand()函数的返回值决定。START_STICKY适用于一个服务需要被明确地指定启动或停止的情况。而whileSTART_NOT_STICKY或START_REDELIVER_INTENT使用于一个服务需要一直运行直到处理完它们收到的命令。 客户端也可以使用Context.bindService()去取得与一个Service的长连接。它同样会创建一个Service,如果Service没有运行(调用onCreate()来创建),但不会调用onStartCommand()。客户端将会接收从service的onBind(Intent)方法返回的IBinder对象,从而客户端就可以调用service上的方法了。只要客户端和service的连接一建立,service就会一直保持运行状态(无论客户端是否有保存service的IBinder引用)。通常IBinder返回的是一个用aidl写好了的复杂接口。 一个service可以同时被启动和绑定。在这种情况下,系统会保持一个带有Context.BIND_AUTO_CREATE标识的service一直运行只要他被启动或者有一个或多个连接跟这个服务绑定着。一旦没有被启动和连接,service的onDestroy()就会被调用然后service就会被终止。在onDestroy()方法返回前,所有的线程和资源都应该被清理掉。 Process Lifecycle 前面我们讲到,Service其实是运行在寄居在应用程序的进程当中的,也就是说当应用程序的进程被销毁的时候,Service也就被销毁了。当然,Android系统会尽力保证带有Service的应用程序进程存活尽可能长的时候,只要进程中有Service已经启动或者有别的客户端需要使用着Service的服务。当Android系统内的内存不足,需要杀死一些进程来释放内存时,在下面情况中,线程的优先级会因为Service而增高,进而减少被系统回收的可能性: 如果进程中的Service正在执行onCreate(),onStartCommand(), 或onDestroy()方法,那么这个进程就会变成前台处理(foreground process)进程,进而能够保证进程不会被回收。 如果一个Service被启动了,那么他的宿主进程就会被系统认为比当前用户正在使用的的应用程序的进程更不重要,但比其他的后台进程更重要。因为通常用户当前只使用一小部分进程(也就是用户看得见的进程),这意味着Service所在的进程不应该被回收掉,除非系统内存极度缺乏。 如果一个客户端(Client)跟Service绑定,那么这个Service的宿主进程会被系统认为跟客户端进程是同等重要的,也就是,如果一个客户端程序对用户是可见的(也就是正在被使用),那么Service自身也会被认为是可见的。 已经开始运行了的Service可以使用startForeground(int, Notification)API将当前进程放到前台状态(Foreground state),这样系统就会认为他是用户想要使用的进程,因此就不会成为低内存时的待回收进程。(但是理论上,在内存极度匮乏的情况下,这个进程仍有可能被回收。实际上,一般不会有这么极端的情况)。 注意,这说明当我们的Service正在运行的时候,它都不会被系统杀死,除非内存快满了。如果Service被杀掉了,那么随后系统还会尝试着重新启动Service。这样子,我们就必须考虑到如果我们实现onStartCommand()方法,用异步或者其他线程来完成Service的任务,那么我们就可能需要使用START_FLAG_REDELIVERY让系统重新传递一个Intent,以便在Service重新启动后,Intend会丢失。 在同一个进程中的应用程序组件(application components)像Service(或者Activity)可以增加进程在所有进程中的重要性,而不是仅仅增加Service的重要性。 补充说明: 前面谈到Service是由系统进行调度的,那么对我们来讲有什么意义呢?他又体现在什么地方呢? 因为Service是由系统进行调度的,那么它的生命周期与Activity的生命周期也就无关了,也就是假设ServiceA是由ActivityA启动的,即使当ActivityA因为某种原因调用了OnDestroy()方法将自己销毁掉之后,ServiceA依然欢快地运行着。 本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/p/3322562.html如需转载请自行联系原作者 kissazi2

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

Cocoa编程学习笔记之MVC

Cocoa 使用了一种修改版本的MVC模式来处理GUI的显示。MVC模式(自1979年以来)已经出现很长时间了,它皆在分离显示用户界面所需的大量任务,并处理用户交互。正如名称所蕴含的,MVC具有三个主要部分,Model(模型)、View(视图)和Controller(控制器): 模型——模型是特定于领域的数据表现形式。比如说,我们正在创建一个任务列表应用程序。你可能会有一个Task对象的集合,书写为List。 你或许把这些数据保存在数据库、XML文件,或者甚至从Web Service中得到,不过MVC不那么关心它们是在何处/如何来持久保存的(乃至它们是什么)。相反,它特别专注于如何显示这些数据,并处理与用户交互的,好的模型类不包括任何有关用户界面的内容,可以在多个应用程序中使用。视图——视图代表了数据如何实际地显示出来。在我们这个假设的任务应用程序中,会在一个网页(以HTML的方式)中来显示这些任务,也会在一个WPF页面中(以XAML的方式)来显示,或者在一个iPhone应用程序中显示为UITableView 。如果用户点击某个任务,要删除之,那么视图通常会触发一个事件,或对Controller(控制器)进行一个回调,好的视图类是通用类,可以在多个应用中使用。控制器——控制器是模型和视图间的粘合剂,负责控制整个应用的流程。控制器的目的就是获取模型中的数据,告知视图来显示。控制器还侦听着视图的事件,在用户选中一个任务来删除的时候,控制着任务从模型中删除。通过分离显示数据、持久化数据和处理用户交互的职责,MVC模式有助于创建易于理解的代码。而且,它促进了视图和模型的解耦,以便模型能被重用。例如,在你的应用程序中,有两个界面,基于Web的和WPF的,那么你可以在两者中都使用同样的模型定义代码。 因而,在很多MVC框架中不管具体的工作方式如何,基本原理都大致如此的。然而,在Cocoa(及Cocoa Touch)中,还是或多或少有所不同,苹果用MVC来代表Views(视图)、View Controller(视图控制器)和Models(模型);但是在不同的控件中,它们却不是完全一致的,实现的方式也不太一样。 在Objective-C/Cocoa的世界里,我们建立的controller通常是指应用程序(Application)的委托(Delegate),或者可以简单称做app delegate。当你在Objective-C里面建立一个app delegate的时候,这个delegate可以做为你所有model和view的controller,或者你也可以为不同的model和view分别创建controller。 本文来自云栖社区合作伙伴“doNET跨平台”,了解相关信息可以关注“opendotnet”微信公众号

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

spring cloud 学习(5) - config server

分布式环境下的统一配置框架,已经有不少了,比如百度的disconf,阿里的diamand。今天来看下spring cloud对应的解决方案: 如上图,从架构上就可以看出与disconf之类的有很大不同,主要区别在于: 配置的存储方式不同 disconf是把配置信息保存在mysql、zookeeper中,而spring cloud config是将配置保存在git/svn上 (即:配置当成源代码一样管理) 配置的管理方式不同 spring cloud config没有类似disconf的统一管理界面,既然把配置都当成git之类的源码来看待了,git的管理界面,就是配置的管理界面 配置变化的通知机制不同 disconf中配置变化后,依赖zk的事件watcher来通知应用,而spring cloud config则是依赖git每次push后,触发webhook回调,最终触发spring cloud bus(消息总线),然后由消息总线通知相关的应用。 另外,spring cloud config server本身也是一个微服务,跟其它的微服务一样,也可以注册到eureka server上,让其它使用方从注册中心来发现,单纯从解决的问题/场景来看,disconf与spring cloud config server是高度重合的,很难说哪个好,那个差,只是设计哲学不同。 但有一点,从配置变化的通知机制上看,如果有100个应用节点,都依赖于统一配置,如果修改了配置,只想让某几个节点"灰度"更新配置,spring cloud config server更容易做到,这一点相对disconf更灵活(后面会详细讲解)。 使用步骤: 一、在git/svn上创建一个配置项目(用于保存配置文件) 以https://github.com/yjmyzz/spring-cloud-config-repository 这个为例,上面就放了几个配置文件(推荐用新的yml格式,对中文支持更好码)。 application.yml里的内容如下: demo: title: "default title" 其它几个文件application_xxx.yml,里面的xxx,代表不同的profile. 二、创建config-server微服务 2.1 添加依赖项 dependencies { compile 'org.springframework.cloud:spring-cloud-starter-eureka' compile 'org.springframework.cloud:spring-cloud-config-server' compile 'org.springframework.boot:spring-boot-starter-actuator' } 关键是第2个依赖项 2.2 application.yml spring: application: name: config-server profiles: active: server1 cloud: config: server: git: uri: https://github.com/yjmyzz/spring-cloud-config-repository # username: ***** # password: ***** eureka: instance: prefer-ip-address: true instance-id: ${spring.application.name}:${server.port} client: service-url: defaultZone: http://yjmyzz:123456@server1:8100/eureka,http://yjmyzz:123456@server2:8200/eureka management: security: enabled: false 注意上面的cloud.config.server这段,里面配置了git配置项目的位置。另外:config-server服务本身也需要HA,所以本示例中起了2个实例,分别对应server1、server2 这二个profile,用不同的端口,在本机跑2个实例,以模拟高可用。 application-server1.yml server: port: 8004 application-server2.yml server: port: 8005 2.3 main入口类 package com.cnblogs.yjmyzz.spring.cloud.study.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * Created by yangjunming on 2017/7/5. */ @SpringBootApplication @EnableEurekaClient @EnableConfigServer public class ConfigServer { public static void main(String[] args) { SpringApplication.run(ConfigServer.class, args); } } 关键是@EnableConfigServer 这个注解。 2.4 跑起来看看 可以看到2个config-server已经注册到eureka上了,然后单独浏览一下: http://localhost:8004/application-dev.yml 已经把git上的application-dev.yml的内容输出了。 三、使用config-server 3.1 在之前的service-provider中添加依赖项 compile 'org.springframework.cloud:spring-cloud-starter-config' 3.2 创建一个简单的配置类 package com.cnblogs.yjmyzz.spring.cloud.study.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * Created by yangjunming on 2017/7/5. */ @Component @Data @ConfigurationProperties(prefix = "demo") public class DemoConfig { private String title; } 然后找一个示例服务,使用这个配置: package com.cnblogs.yjmyzz.spring.cloud.study.service.impl; import com.cnblogs.yjmyzz.spring.cloud.study.api.UserService; import com.cnblogs.yjmyzz.spring.cloud.study.config.DemoConfig; import com.cnblogs.yjmyzz.spring.cloud.study.dto.UserDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService { @Autowired DemoConfig config; @Override public UserDTO findUser(Integer userId) { UserDTO user = new UserDTO(); user.setUserId(userId); user.setUserName("菩提树下的杨过(" + config.getTitle() + ")"); return user; } } 3.3 添加bootstrap.yml 配置文件 spring: application: name: application cloud: config: profile: dev label: master discovery: enabled: true service-id: config-server eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://yjmyzz:123456@server1:8100/eureka,http://yjmyzz:123456@server2:8200/eureka 注意spring.cloud这一节的内容,里面指定了profile为dev,读取的git配置文件分支为master,同时允许从eureka上自动发现config-server这个实例。另外 spring.applicatin.name 即为配置文件的名称(即:application_xxx.yml) 3.4 跑起来看看 说明已经从config-server取到了配置。 四、配置更新 4.1 Controller上添加@RefreshScope @RestController @RefreshScope public class UserController { @Autowired private UserService userService; @GetMapping("/user/{id}") public UserDTO findUser(@PathVariable Integer id) { return userService.findUser(id); } } 这个注解,根据源码上的说法:Beans annotated this way can be refreshed at runtime and any components that are using them will get a new instance on the next method call, fully initialized and injected with all dependencies. 使用该注解后,可以在运行时直接刷新Bean,并在下次方法调用时,得到一个全新的实例。 4.2 手动刷新/refresh 可以尝试把git配置项目里的application-dev.yml修改下内容,再浏览刚才的http://localhost:8001/user/1 发现内容并没有变化。 http://localhost:8001/refresh 手动向这个地址,发一个post请求(可以用postman或 curl -d ''http://localhost:8001/refresh),可以看到 说明demo.title这个配置项被刷新了,再浏览http://localhost:8001/user/1 可以看到有变化了 但是这样显然不是个办法,比如有10个service-provider组成的集群,如果要1台台手动刷新,太low了(除了做配置灰度更新,可以先刷新1台这种场景外) 4.3 集成spring cloud bus来批量刷新 spring cloud bus目前仅支持rabbitmq 及 kafka,我们以kafka为例,先在service-provider的application.yml里,加入下面的配置 然后依赖项里,加入: compile 'org.springframework.cloud:spring-cloud-starter-bus-kafka' 注:关于kafka的环境搭建,网上有很多资料,大家可以参考下。 配置好这些后,本机启动kafka,然后再重启service-provider,就会多出一个/bus/refresh的端点,即:http://xxx:port/bus/refresh ,只要向集群中的任何一台机器的/bus/refresh发起post请求,就会同步刷新其它所有节点。原理大致就是,这台机器会发一条消息到kafka中,然后其它机器都是挂在消息总线上的,也会监听到该消息,然后刷新各自的配置。 最后一个问题:就算有/bus/refresh,也需要有人或系统触发。这个很好解决,github或gitlab上一般都有webhook功能,可以配置在代码push时,触发一些地址的回调。 这样,只要配置的代码提交了,就会触发自动刷新。 注:低版本的spring-cloud-dependencies有一个严重bug,调用/bus/refresh后,会导致所有服务节点,从eureka server的实例列表中永久下线,无法自动恢复,除非再次访问某个服务的/health端点,建议使用Dalston.SR2 或以上版本。 示例源代码:https://github.com/yjmyzz/spring-cloud-demo

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

Hadoop源码学习之HDFS(一)

Hadoop的HDFS可以分为NameNode与DataNode,NameNode存储所有DataNode中数据的元数据信息。而DataNode负责存储真正的数据(数据块)信息以及数据块的ID。 NameNode上并不永久保存哪个DataNode上有哪些数据块的信息,而是通过DataNode启动时的上报,来更新NameNode上的映射表。 那么从DataNode上开始一点一点看: 在存储层面,Storage抽象类继承了StorageInfo。在StorageInfo中存储了layoutVersion:版本号,namenodeID是Storage的ID,cTime,creation time,storageType。

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

iOS学习之UIActionSheet的使用

UIActionSheet是在iOS弹出的选择按钮项,可以添加多项,并为每项添加点击事件。 为了快速完成这例子,我们打开Xcode 4.3.2, 先建立一个single view application。然后再xib文件添加一个button,用来弹出sheet view。 1、首先在.h文件中实现协议 加代码的地方在@interface那行的最后添加<UIActionSheetDelegate>,协议相当于java里的接口,实现协议里的方法。 [cpp] view plain copy @interfacesheetviewViewController:UIViewController<UIActionSheetDelegate> @end 2、添加button,命名button为showSheetView. 3、为button建立Action映射,映射到.h文件上,事件类型为Action ,命名为showSheet。 4、在.m文件上添加点击事件代码 图的效果是这样的: [cpp] view plain copy -(IBAction)showSheet:(id)sender{ UIActionSheet*actionSheet=[[UIActionSheetalloc] initWithTitle:@"title,nil时不显示" delegate:self cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:@"第一项",@"第二项",nil]; actionSheet.actionSheetStyle=UIActionSheetStyleBlackOpaque; [actionSheetshowInView:self.view]; } actionSheet.actionSheetStyle=UIActionSheetStyleBlackOpaque;//设置样式 参数解释: cancelButtonTitle destructiveButtonTitle是系统自动的两项。 otherButtonTitles是自己定义的项,注意,最后一个参数要是nil。 [actionSheetshowInView:self.view];这行语句的意思是在当前view显示Action sheet。当然还可以用其他方法显示Action sheet。 对应上面的图和代码,一目了然了把 5、接下来我们怎么相应Action Sheet的选项的事件呢? 实现协议里的方法。为了能看出点击Action sheet每一项的效果,我们加入UIAlertView来做信息显示。下面是封装的一个方法,传入对应的信息,在UIAlertView显示对应的信息。 [cpp] view plain copy -(void)showAlert:(NSString*)msg{ UIAlertView*alert=[[UIAlertViewalloc] initWithTitle:@"ActionSheet选择项" message:msg delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil]; [alertshow]; } 那相应被Action Sheet选项执行的代码如下: [cpp] view plain copy (void)actionSheet:(UIActionSheet*)actionSheetclickedButtonAtIndex:(NSInteger)buttonIndex { if(buttonIndex==0){ [selfshowAlert:@"确定"]; }elseif(buttonIndex==1){ [selfshowAlert:@"第一项"]; }elseif(buttonIndex==2){ [selfshowAlert:@"第二项"]; }elseif(buttonIndex==3){ [selfshowAlert:@"取消"]; } } -(void)actionSheetCancel:(UIActionSheet*)actionSheet{ } -(void)actionSheet:(UIActionSheet*)actionSheetdidDismissWithButtonIndex:(NSInteger)buttonIndex{ } -(void)actionSheet:(UIActionSheet*)actionSheetwillDismissWithButtonIndex:(NSInteger)buttonIndex{ } 可以看到 buttonIndex 是对应的项的索引。 看到那个红色的按钮没?那是ActionSheet支持的一种所谓的销毁按钮,对某户的某个动作起到警示作用, 比如永久性删除一条消息或图像时。如果你指定了一个销毁按钮他就会以红色高亮显示: actionSheet.destructiveButtonIndex=1; 与导航栏类似,操作表单也支持三种风格: UIActionSheetStyleDefault //默认风格:灰色背景上显示白色文字 UIActionSheetStyleBlackTranslucent //透明黑色背景,白色文字 UIActionSheetStyleBlackOpaque //纯黑背景,白色文字 用法: actionSheet.actionSheetStyle=UIActionSheetStyleBlackOpaque;//设置样式 我选sheet 里的第一项,显示如下: 6、注意事项 在开发过程中,发现有时候UIActionSheet的最后一项点击失效,点最后一项的上半区域时有效,这是在特定情况下才会发生,这个场景就是试用了UITabBar的时候才有。解决办法: 在showView时这样使用,[actionSheet showInView:[UIApplication sharedApplication].keyWindow];或者[sheet showInView:[AppDelegate sharedDelegate].tabBarController.view];这样就不会发生遮挡现象了。 代码获取:http://download.csdn.net/detail/totogo2010/4343267 https://github.com/schelling/YcDemo 著作权声明:本文由http://blog.csdn.net/totogo2010/原创 本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3498920.html,如需转载请自行联系原作者

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

Android Bitmap和Canvas学习笔记

位图是我们开发中最常用的资源,毕竟一个漂亮的界面对用户是最有吸引力的。 1. 从资源中获取位图 可以使用BitmapDrawable或者BitmapFactory来获取资源中的位图。 当然,首先需要获取资源: Resources res=getResources(); 使用BitmapDrawable获取位图 使用BitmapDrawable (InputStream is)构造一个BitmapDrawable; 使用BitmapDrawable类的getBitmap()获取得到位图; // 读取InputStream并得到位图 InputStream is=res.openRawResource(R.drawable.pic180); BitmapDrawable bmpDraw=new BitmapDrawable(is); Bitmap bmp=bmpDraw.getBitmap(); 或者采用下面的方式: BitmapDrawable bmpDraw=(BitmapDrawable)res.getDrawable(R.drawable.pic180); Bitmap bmp=bmpDraw.getBitmap(); 使用BitmapFactory获取位图 (Creates Bitmap objects from various sources, including files, streams, and byte-arrays.) 使用BitmapFactory类decodeStream(InputStream is)解码位图资源,获取位图。 Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); BitmapFactory的所有函数都是static,这个辅助类可以通过资源ID、路径、文件、数据流等方式来获取位图。 以上方法在编程的时候可以自由选择,在Android SDK中说明可以支持的图片格式如下:png (preferred), jpg (acceptable), gif (discouraged),和bmp(Android SDK Support Media Format)。 2. 获取位图的信息 要获取位图信息,比如位图大小、像素、density、透明度、颜色格式等,获取得到Bitmap就迎刃而解了,这些信息在Bitmap的手册中,这里只是辅助说明以下2点: 在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他的,比如说RGB_555,在开发中可能需要注意这个小问题; Bitmap还提供了compress()接口来压缩图片,不过AndroidSAK只支持PNG、JPG格式的压缩;其他格式的需要Android开发人员自己补充了。 3. 显示位图 显示位图可以使用核心类Canvas,通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。当然,也可以通过BitmapDrawable将位图显示到View中。 转换为BitmapDrawable对象显示位图 // 获取位图 Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); // 转换为BitmapDrawable对象 BitmapDrawable bmpDraw=newBitmapDrawable(bmp); // 显示位图 ImageView iv2 = (ImageView)findViewById(R.id.ImageView02); iv2.setImageDrawable(bmpDraw); 使用Canvas类显示位图 这儿采用一个继承自View的子类Panel,在子类的OnDraw中显示 public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new Panel(this)); } class Panel extends View{ public Panel(Context context) { super(context); } public void onDraw(Canvas canvas){ Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bmp, 10, 10, null); } } } 4. 位图缩放 (1)将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎一样:drawBitmap(Bitmapbitmap,Rectsrc,Rectdst,Paintpaint)。 (2)在原有位图的基础上,缩放原位图,创建一个新的位图:CreateBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) (3)借助Canvas的scale(float sx, float sy) (Preconcat the current matrix with the specified scale.),不过要注意此时整个画布都缩放了。 (4)借助Matrix: Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); Matrix matrix=new Matrix(); matrix.postScale(0.2f, 0.2f); Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), bmp.getHeight(),matrix,true); canvas.drawColor(Color.BLACK); canvas.drawBitmap(dstbmp, 10, 10, null); 5. 位图旋转 同样,位图的旋转也可以借助Matrix或者Canvas来实现。 Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); Matrix matrix=new Matrix(); matrix.postScale(0.8f, 0.8f); matrix.postRotate(45); Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), bmp.getHeight(),matrix,true); canvas.drawColor(Color.BLACK); canvas.drawBitmap(dstbmp, 10, 10, null); 旋转效果: 6.图片水印的生成方法 生成水印的过程。其实分为三个环节:第一,载入原始图片;第二,载入水印图片;第三,保存新的图片。 /** * create thebitmapfrom a byte array * * @param src thebitmapobject you want proecss * @param watermark the water mark above the src * @return return abitmapobject ,if paramter's length is 0,return null */ privateBitmap createBitmap( Bitmap src, Bitmap watermark ) { String tag ="createBitmap"; Log.d( tag,"create a newbitmap"); if( src ==null) { returnnull; } intw = src.getWidth(); inth = src.getHeight(); intww = watermark.getWidth(); intwh = watermark.getHeight(); //create the new blankbitmap Bitmap newb = Bitmap.createBitmap( w, h, Config.ARGB_8888 );//创建一个新的和SRC长度宽度一样的位图 Canvas cv =newCanvas( newb ); //draw src into cv.drawBitmap( src,0,0,null);//在 0,0坐标开始画入src //draw watermark into cv.drawBitmap( watermark, w - ww +5, h - wh +5,null);//在src的右下角画入水印 //save all clip cv.save( Canvas.ALL_SAVE_FLAG );//保存 //store cv.restore();//存储 returnnewb; } 7.Canvas的save和restore onDraw方法会传入一个Canvas对象,它是你用来绘制控件视觉界面的画布。 在onDraw方法里,我们经常会看到调用save和restore方法,它们到底是干什么用的呢? save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。 save和restore要配对使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error。save和restore之间,往往夹杂的是对Canvas的特殊操作。 例如:我们先想在画布上绘制一个右向的三角箭头,当然,我们可以直接绘制,另外,我们也可以先把画布旋转90°,画一个向上的箭头,然后再旋转回来(这种旋转操作对于画圆周上的标记非常有用)。然后,我们想在右下角有个20像素的圆,那么,onDraw中的核心代码是: int px = getMeasuredWidth(); int py = getMeasuredWidth(); // Draw background canvas.drawRect(0, 0, px, py, backgroundPaint); canvas.save(); canvas.rotate(90, px/2, py/2); // Draw up arrow canvas.drawLine(px / 2, 0, 0, py / 2, linePaint); canvas.drawLine(px / 2, 0, px, py / 2, linePaint); canvas.drawLine(px / 2, 0, px / 2, py, linePaint); canvas.restore(); // Draw circle canvas.drawCircle(px - 10, py - 10, 10, linePaint); 效果如图1所示: 如果我们不调用save和restore会是什么样子呢?如图2所示: 从这两个图中,我们就能看到圆圈位置的明显差异。不进行Canvas的save和restore操作的话,所有的图像都是在画布旋转90°后的画布上绘制的。当执行完onDraw方法,系统自动将画布恢复回来。save和restore操作执行的时机不同,就能造成绘制的图形不同。 本文转自feisky博客园博客,原文链接:http://www.cnblogs.com/feisky/archive/2010/01/10/1643460.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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文件系统,支持十年生命周期更新。

用户登录
用户注册