响应式编程思想概述
- 响应式编程:是一种面向数据流和变化传播的编程范式
- 数据流:只能以事先规定好的顺序被读取一次的数据的一个序列
- 变化传播:类似观察者模式,变化了要通知别人
RxJava源码分析
基本元素
RxJava是一个基于回调的异步的库,是一个基于事件分发和消息传递的库
RxJava是一个基于回调的异步的库,是一个基于事件分发和消息传递的库
领域特定语言DSL(Domain Specific Language):其核心思想为"求专不求全,解决特定问题",
Groovy: http://www.groovy-lang.org/
Groovy:是一种基于JVM的敏捷开发语言,结合了Python、Ruby等脚本语言的许多强大特性,可以与Java完美结合,使用Java的所有库;
优势:一种更加敏捷的编程语言;入门非常容易,但是功能非常强大;既可以作为编程语言也可以作为脚本语言;熟练掌握Java的人会非常容易掌握Groovy
Groovy开发环境搭建:
java平台上有各种语言的翻版,例如kotlin对c#,scala对haskell,Clojure对lisp,groovy对ruby
1 | export PATH=$PATH:/usr/groovy-2.5.5/bin |
1 | //Java版本 |
1 | //Groovy版本 |
无可扩展字符串时以上3种方式的String都是java.lang.String的子类,编码过程中String和GString是可以通用的,更多从方便使用角度考虑即可
Groovy字符串方法介绍
1 | def str = "Groovy",str2 = "Hello",str3= "Hello minus" |
逻辑控制:单步顺序执行|if/else|switch-case|while|for,基本和Java操作一致,针对Groovy扩展介绍如下:
1 | //switch-case |
for循环控制
1 | //对范围的for循环 |
闭包的使用
1 | int fab1(int number){ |
1 | def str = "the 2 and 3 is 5" |
1 | def scriptClosure = { |
总结:this、owner、delegate的值在大多数情况都是一样的,在嵌套闭包中this的值和owner、delegate的值不一致,只有在给delegate赋值后owner和delegate的值才不一致
闭包的委托策略
1 | class Student{ |
map的定义:def colors=[“red”:1,“blue”:2];def colors=[red:1,blue:2]
索引map:println colors.red;println colors[“red”];
添加map:colors.yellow=3 //Groovy中map可以添加不同类型的数据:colors.complex =[a:1,b:2]
遍历map: list.each{def tmp,int index -> …} list.eachWithIndex{ key,value,index -> …}
查找map: any find findAll every
分组map: groupBy{}
排序map:sort
范围Range:定义 def range = 1…10;println range[0];range.contains(10);println range.from;println range.to
Range继承自java.util.List
1 | switch(number){ |
元编程(Metaprogramming)是指某类计算机程序的编写,这类计算机程序编写或者操纵其他程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作。很多情况下与手工编写全部代码相比工作效率更高。编写元程序的语言称之为元语言,被操作的语言称之为目标语言。一门语言同时也是自身的元语言的能力称之为反射
元编程通常有两种方式起作用。一种方式是通过应用程序接口(API)来暴露运行时引擎的内部信息。另一种方法是动态执行包含编程命令的字符串。因此,“程序能编写程序”。虽然两种方法都能用,但大多数方法主要靠其中一种。
1 | class Baby { |
结合上图理解:Java中对象方法的调用没有上图否流程分支,在Groovy中对象方法调用有否分支调用,上例中通过注释invokeMethod、methodMissing方法查看运行效果,通过以下代码可动态添加对象属性和方法:
1 | Baby.metaClass.sex = "male" |
通过ExpandoMetaClass.enableGlobally()设置让动态添加方法全局启用
1 | ''' |
Gradle是一款最新的,功能强大的构建工具,使用程序代替传统的xml配置,项目构建更加灵活,有丰富的第三方库
gradle组成:groovy核心语法+build script block+gradle api
执行./gradlew clean 观察执行过程,其生命周期包括:初始化、配置、执行
在项目的build.gradle中添加如下
1 | //在配置阶段开始之前的回调 |
./gradlew projects //查看工程Project数量,学会区分Project与module及根Project与子Project,每个Project必须有一个build.gradle文件
Project API组成:
./gradlew projects可实现显示所有项目,自我实现如下:
1 | def getProjects(){ |
task相关API
属性相关API
1 | if(hasProperty('isLoadTest')? isLoadTest.toBoolean() : false){ |
自定义属性的两种方式:ext方式+gradle.properties中定义
4. file相关API
1 | //文件/文件夹拷贝 |
gradle生命周期API
其他API
1 | buildscript { |
依赖传递:A模块依赖B模块,B模块依赖C模块,如果A模块也需要C模块功能,不需依赖使用,防止B修改后去掉C依赖而导致错误,可在A中引入C模块,通过exclude排除依赖,transitive禁止依赖传递
占位编译provided:A.类库只在编译阶段起作用 B.父项目已引入类库,子项目直接使用父项目类库,但为了子项目编译通过使用占位编译
1 | task abc() { |
执行:./gradlew abc
1 | task("abcd") { |
通过TaskContainer创建
1 | this.tasks.create("aa"){ |
Task创建之后可在开发工具的gradle插件重查找到task,如果没有设置group,则默认在other分组中,更多配置可通过task源码查看
2. Task执行详解
doFirst/doLast执行阶段执行,否则在配置阶段执行
1 | task aa{ |
编写一个统计build时长的task
app.gradle中编写:
1 | def startBuilderTime,endBuilderTime |
./gradlew build执行查看结果
3. Task的依赖及执行顺序
1 | task t1() { doLast{println 'task t1'} } |
1 | ext{ |
destFile作为writerTask输出结果输入到readTask
1 | task t1() { doLast{println 'task t1'} } |
通过./gradlew t2 t1查看执行结果
4. Task类型
详见官方文档:https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Delete.html#org.gradle.api.tasks.Delete
5. 构建到生命周期
1 | this.project.afterEvaluate {project -> |
1 | if(hasProperty('isLoadTest')? isLoadTest.toBoolean() : false){ |
1 | //修改.so等jnilibs的存放位置 |
gradle插件: https://avatarqing.gitbooks.io/gradlepluginuserguidechineseverision/content/introduction/README.html
varints变体
1 | * 官网网站:http://cordova.apache.org/ |
Apache Cordova是一个开源的移动开发框架。允许你用标准的web技术-HTML5,CSS3和JavaScript做跨平台开发。 应用在每个平台的具体执行被封装了起来,并依靠符合标准的API绑定去访问每个设备的功能,比如说:传感器、数据、网络状态等
注意:当你创建一个Cordova项目它不存在任何插件。这是新的默认行为。任何你需要的组件,哪怕是核心组件,你也必须明确添加。
1 | export ANDROID_HOME=/Users/Neel/Documents/Softwares/adt-bundle-mac-x86_64-20140321/sdk |
1 | CLI命令概要 |
App要接触设备级别的特性,就需要你添加插件了.个插件 通过JavascriptAPI暴露原生SDK功能。插件通常由npm分发(http://cordova.axuer.com/plugins/),一些关键的API由Apache Cordova开源项目提供并且这些插件是作为[核心插件API]的.
顶级merges目录提供了特定平台部署特定资源的地方。每个特定平台在merges中的子目录反映了www 源代码树中的结构, 允许你重写和添加文件。
存放各个平台特殊的文件,会和www进行合并编译,相同的文件merges下的文件优先。
比如:
1 | merges/ |
编译成iOS应用的话,包含merges/ios/app.js;而Android应用的话,包含www/app.js、merges/android/android.js
存放自定义cordova命令的脚本文件。每个project命令都可以定义before和after的Hook,比如:before_build、after_build。
Hook可以采用任何编程语言来写,Cordova CLI采用的是Node.js,所以一般都是用它来写
1 | Android API级别查看:http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels |
打开Android SDK Manager (例如,在终端上运行`android),并确保下面已经安装:
Cordova的Android项目可以被Android IDEAndroid Studio打开;
如果你想使用Android Studio内置的Android调试/分析工具或者你要开发Android插件这是十分有用的
在Android Studio中打开Cordova的Android项目:
==注意==:当在Android studio里打开你的项目,建议你不要编辑你的代码在IDE中。这会在 platforms目录中编辑你的代码(而不是 www),并且变化将会被重写。而是编辑www目录并通过运行cordova build来拷贝过来你的变化。
6. Cordova和Android的生命周期
Cordova事件 | 粗略的Android等效 | 含义 |
---|---|---|
deviceready | onCreate() | 应用程序开始(不是从背景) |
pause | onPause() | 应用程序移动到背景 |
resume | onResume() | 应用程序返回到前景 |
关于生命周期:
在Android设备中,操作系统可以选择在后台杀死活动来释放资源,如果当前设备运行程序的内存过低。由于这个原因,你的应用程序知道生命周期被触发并维持任何确保用户在离开应用程序用户上下文不丢失的状态,是必须的。
应该通过bindEvents 方法来注册应用程序回调来回应生命周期事件来保存状态。保存什么息和怎么保存信息由你决定,但是你要确保保存足够的信息,来精确的恢复到用户离开的地方
1 | // 这个状态代表了应用程序的状态并且会在onResume()和onPause()中保存和恢复 |
对启动画面(splash screen)的支持已经被移动到Cordova自己的插件中了,http://cordova.axuer.com/docs/zh-cn/latest/reference/cordova-plugin-splashscreen/
当工作在CLI工作流中,你可以通过
元素(config.xml)定义你的app图标。如果没用指定图标将使用ApacheCordova的logo.
属性 | 描述 |
---|---|
src | 必要 图片文件位置,相对于项目根路径 |
platform | 可选 目标平台 |
width | 可选 图片的像素宽度 |
height | 可选 图片的像素高度 |
density | 可选 |
Android | 指定图标密度 |
target | 可选 |
Windows | 图片文件和所有多渲染目标(MRT)伙伴的目标文件名 |
1 | <icon src="res/icon.png" /> //用来定义用于所有平台的唯一默认图标 |
Android
1 | <platform name="android"> |
IOS
1 | <platform name="ios"> |
LocalStorage提供了简单和同步的键值对存储方式,而且在各个Cordova平台,底层的WebView实现都支持它。
LocalStorage可以通过window.localStorage访问到。以下的代码片段展示了返回的storage对象的最重要的几个方法。
1 | var storage = window.localStorage; |
外部域是应用无法控制的,而域名白名单则是一种控制访问外部域的安全模型。Cordova提供了一项可配置的安全策略来定义哪些外部站点可以访问。默认情况下,新的app被配置成可以访问任何站点。然而在发布到生产环境前,你应该制定一份白名单,限制应用可以访问的域名和子域名。
可以使用cordova-plugin-whitelist实现,虽然实现白名单插件是可能的,但还是不推荐这样做,除非你的app有非常明确的安全策略需要
依赖于使用app的config.xml文件里的
Cordova给我们提供了很多的事件,可以在应用程序中使用。应用程序代码中可以添加这些事件的监听。事件相关定义都在www/js/index.js中
支持的平台/
事件 | android | ios | 备注 |
---|---|---|---|
deviceready | Cordova设备API准备好并可以访问的信号 | ||
pause | 当原生平台把应用程序放入后台这个pause事件会触发,通常是用户切换到了不同的应用程序 | ||
resume | 当原生平台将应用程序从后台运行拉出resume事件就会触发 | ||
backbutton | X | 当用户按下返回按钮事件触发 | |
menubutton | X | 当用户按下菜单按钮事件触发 | |
searchbutton | X | 当用户按下搜索按钮事件触发 | |
startcallbutton | X | X | 当用户按下通话按钮事件触发 |
endcallbutton | X | X | 当用户按下挂断通话按钮事件触发 |
volumedownbutton | X | 当用户按下降低声音按钮事件触发 | |
volumeupbutton | X | 当用户按下增加声音按钮事件触发 |
http://cordova.axuer.com/docs/zh-cn/latest/config_ref/index.html
http://ionicframework.com/docs/components/#overview
http://www.runoob.com/ionic/ionic-tutorial.html
https://creator.ionic.io/app/dashboard/projects
1 | ionic run ios --device |
ios-sim命令行工具。
ios-sim 是一个可以在命令控制iOS模拟器的工具。利用这个命令,我们可以启动一个模拟器,安装app,启动app,查询iOS SDK。它可以使我们像自动化测试一样不用打开Xcode。
1 | Usage: ios-sim <command></command> <options> [--args ...] |
ios-sim launch /Users/YDZ/Desktop/app.app --devicetypeid iPhone-6s
其中,/Users/YDZ/Desktop/app.app这个是设计师收到app之后的路径。–devicetypeid参数后面是给定一个模拟器的版本。
只需要把上面的命令发给设计师,无脑粘贴到命令行,装好app的模拟器就会自动启动,打开app了。
大公司的话可以应该有两个账号,一个上appstore的开发账户,这个严格保密。还有一个打线下包的企业账号,这样就能达到需求了
RPC(即Remote Procedure Call,远程过程调用)和HTTP(HyperText Transfer Protocol,超文本传输协议)
RPC主要工作在TCP协议之上,而HTTP服务主要是工作在HTTP协议之上,我们都知道HTTP协议是在传输层协议TCP之上的,所以效率来看的话,RPC当然是要更胜一筹
REST,即Representational State Transfer的缩写。翻译过来是表现层状态转换。
满足REST约束条件和原则的架构,就被称为是RESTful架构
restful首先是要求必须把所有的应用定义成为“resource”,然后只能针对资源做有限的四种操作
有太多现实中需要的API,无法顺当的融入到restful所定义的规范中。
比方说,user login / resetpassword等等
JSON rpc基本上仅是要求所有的请求必须有msg id,有函数名,然后可定义参数,并且区分返回值与异常;也可定义『命名空间』来对函数模块做划分。
restful API仅适用与业务非常简单的场景,比方说,就是为了提供少量数据表单的增删改查。而这种场景实在是太过简单,实际中几乎找不到。
RPC协议性能要高的多,例如Protobuf、Thrift、Kyro等,(如果算上序列化)吞吐量大概能达到http的二倍
对外开放给全世界的API推荐采用RESTful,是否严格按照规范是一个要权衡的问题。要综合成本、稳定性、易用性、业务场景等等多种因素。
内部调用推荐采用RPC方式
以Apache Thrift为代表的二进制RPC,支持多种语言(但不是所有语言),四层通讯协议,性能高,节省带宽。相对Restful协议,使用Thrifpt RPC,在同等硬件条件下,带宽使用率仅为前者的20%,性能却提升一个数量级。但是这种协议最大的问题在于,无法穿透防火墙。
以Spring Cloud为代表所支持的Restful 协议,优势在于能够穿透防火墙,使用方便,语言无关,基本上可以使用各种开发语言实现的系统,都可以接受Restful 的请求。 但性能和带宽占用上有劣势
业内对微服务的实现,基本是确定一个组织边界,在该边界内,使用RPC; 边界外,使用Restful。这个边界,可以是业务、部门,甚至是全公司
REST 是面向资源的,这个概念非常重要,而资源是通过 URI 进行暴露
URI 的设计只要负责把资源通过合理方式暴露出来就可以了。对资源的操作与它无关,操作是通过 HTTP动词来体现,所以REST 通过 URI 暴露资源时,会强调不要在 URI 中出现动词。
比如:左边是错误的设计,而右边是正确的
1 | GET /rest/api/getDogs --> GET /rest/api/dogs 获取所有小狗狗 |
一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,Client Stub以及Server Stub,这个Stub大家可以理解为存根
1)客户端(Client),服务的调用方。
2)服务端(Server),真正的服务提供者。
3)客户端存根,存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
4)服务端存根,接收客户端发送过来的消息,将消息解包,并调用本地的方法。
目前流行的开源RPC框架:
gRPC是Google;Thrift是Facebook的一个开源项目;Dubbo是阿里集团开源的一个极为出名的RPC框架
RPC框架的好处就显示出来了,首先就是长链接,不必每次通信都要像http一样去3次握手什么的,减少了网络开销;其次就是RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作
RPC服务主要是针对大型企业的,而HTTP服务主要是针对小企业的,因为RPC效率更高,而HTTP服务开发迭代会更快
RPC是分布式架构的核心,按响应方式分如下两种:
同步调用:客户端调用服务方方法,等待直到服务方返回结果或者超时,再继续自己的操作
异步调用:客户端把消息发送给中间件,不再等待服务端返回,直接继续自己的操作。
同步调用的实现方式有WebService和RMI。RMI实际上是Java语言的RPC实现
异步调用的JAVA实现版就是JMS(Java Message Service),目前开源的的JMS中间件有Apache社区的ActiveMQ、Kafka消息中间件,另外有阿里的RocketMQ。
https://blog.csdn.net/u014590757/article/details/80233901
REST使用HTTP+URI+XML /JSON 的技术来实现其API要求的架构风格:HTTP协议和URI用于统一接口和定位资源,文本、二进制流、XML、JSON等格式用来作为资源的表述
RPC架构分为三部分:
服务提供者,运行在服务器端,提供服务接口定义与服务实现类。
服务中心,运行在服务器端,负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。
服务消费者,运行在客户端,通过远程代理对象调用远程服务。
高级选项卡使您能够为客户机或服务器的计算机配置高级概要文件信息。
发送操作超时
用于指定数据库服务器在与客户机建立连接后,完成“向客户机发送”操作的时间 (以秒计)。
建议在客户机出现偶然或异常关闭的环境中设置此参数。如果数据库服务器无法在指定时间内完成发送操作,该服务器将向 sqlnet.log 文件中写入日志条目:ORA-12535:操作超时和 ORA-12608:TNS:发送超时。
在没有此参数的情况下,数据库服务器将继续向处于停机或忙状态而无法接收数据的客户机发送响应。
也可以在客户端设置此参数,以指定客户机在与数据库服务器建立连接后完成“向数据库服务器发送”操作的时间 (以秒计)。在没有此参数的情况下,客户机会继续向请求已处于饱和状态的数据库服务器发送请求。
接收操作超时
用于指定数据库服务器在建立连接后等待客户机数据的时间 (以秒计)。客户机必须在规定时间内发送一些数据。
建议在客户机出现偶然或异常关闭的环境中设置此参数。如果客户机没有在指定时间内发送任何数据,数据库服务器将向 sqlnet.log 文件中写入日志条目:ORA-12535:TNS:操作超时和 ORA-12609:TNS:接收超时。
在没有此参数的情况下,数据库服务器将继续等待已关闭或出现问题的客户机发来数据。也可以在客户端使用此设置,以指定客户机在与数据库服务器建立连接后等待来自数据库服务器的响应数据的时间 (以秒计)。
在没有此参数的情况下,客户机可能长时间等待请求已处于饱和状态的数据库服务器发回的响应。
发送缓冲区大小总计
为会话的发送操作指定缓冲区空间限制。此参数获得 TCP/IP、使用 SSL 的 TCP/IP 以及 SDP 协议的支持。
接收缓冲区大小总计
为会话的接收操作指定缓冲区空间限制。此参数获得 TCP/IP、使用 SSL 的 TCP/IP 以及 SDP 协议的支持。
TNS 超时值
指定发送探测包的时间间隔 (分钟),以检查客户机/服务器连接是否处于活动状态。设置大于 0 的值可确保客户机异常终止时,连接也完全断开。如果探测发现终止的连接或不再使用的连接,将返回一个错误,从而退出服务器进程。此设置是针对数据库服务器的,服务器通常同时处理多个连接。
使用此检测中断连接功能的限制如下:
此功能不允许用于继承的连接。
探测包虽然很小,但它将造成额外的通信量,并致使网络的性能下降。
取决于使用的操作系统,服务器可能需要执行其他处理,以便将连接探测事件与其他发生的事件区分开。这也会导致网络性能的下降。
注:此选项仅适合在服务器上使用。
客户机注册 ID
为该客户机输入一个唯一的标识符。此标识符与任何连接请求一起被传递到监听程序。
监听程序将此标识符包括在其日志文件中。此标识符可以是长度不超过 128 个字符的任何字符串。
登录验证协议版本
用于指定客户机或数据库允许使用的验证协议。 如果客户机和数据库服务器没有匹配的版本,则验证失败,并出现错误。
支持的值包括:
10 代表 10i 验证协议
9 代表 9i 验证协议
8:代表 8i 验证协议
默认值:代表 10i、9i 和 8i 验证协议
10 以外的任何值都会暴露先前各版本的验证协议中存在的缺点。为了实现完全兼容,请将允许登录的版本列表设置为默认值,以便系统能够囊括所有版本的数据库。
关闭 UNIX 信号处理
选择此选项以配置客户机,使其通过禁用信号处理程序将子进程清除传递给 UNIX 的 init 进程。
由于客户机应用程序在内部衍生一个服务器进程,因此客户机应用程序应负责在进程结束时清除该子进程。此服务器进程完成其连接使命后,即成为一个死进程。信号处理程序负责清除这些死进程。
禁用段外中断
选择此选项,可禁用或启用段外中断。
如果取消选择此选项,将使 Oracle Net 能够使用由基础协议提供的紧急数据发送或接收“中断”消息。
如果选择此选项,将禁用使用由基础协议提供的紧急数据发送或接收“中断”消息的功能。一旦启用,此功能将应用到此客户机使用的所有协议中。
版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。
访问权限选项卡使您能够指定允许或拒绝哪些客户机访问数据库。
检查 TCP/IP 客户机访问权限
如果要指定哪些客户机允许和拒绝访问数据库,请选中该复选框。如果要禁用该功能,请取消选中该复选框。如果取消选中该复选框,则允许所有客户机进行访问。
拒绝访问的客户机
输入主机名或 IP 地址来指定拒绝哪些客户机访问数据库。使用逗号分隔同一行中的条目。
允许访问的客户机
输入主机名或 IP 地址来指定允许哪些客户机访问数据库。使用逗号分隔同一行中的条目。
注:允许访问的客户机优先于拒绝访问的客户机。
版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。
事件记录选项卡使您能够设置本计算机上的事件记录参数。如果本计算机是客户机,请使用客户机信息字段。如果本计算机是服务器,请使用服务器信息字段。
日志目录
输入日志文件将写入的目录路径。默认值为 $ORACLE_HOME/network/log (在 UNIX 上) 和 ORACLE_HOME \network\log (在 Windows 平台上)。
日志文件
输入客户机上日志文件的名称。默认名称为 sqlnet.log。
版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。
使用验证选项卡可以配置监听程序的安全性。如果进行了配置,从监听程序控制实用程序发布的授权操作 (如保存配置更改或停止监听程序) 将需要口令。Oracle Net Manager 使您能够设置加密口令。
不需要监听程序操作口令
选择此选项以禁用管理员任务的验证。
需要监听程序操作口令
选择此选项以启用某些管理员任务的验证。然后输入所需口令。默认口令是“oracle”。
注:Oracle Net 允许为每个监听程序配置一个口令。
版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。