Fork me on GitHub
行锋

低头走路,抬头思考


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

  • 搜索

RxJava从源码到应用移动端开发效率秒提速

发表于 2018-10-02 | 分类于 Java

响应式编程思想概述

  • 响应式编程:是一种面向数据流和变化传播的编程范式
  • 数据流:只能以事先规定好的顺序被读取一次的数据的一个序列
  • 变化传播:类似观察者模式,变化了要通知别人

RxJava源码分析

基本元素

RxJava是一个基于回调的异步的库,是一个基于事件分发和消息传递的库

Operator操作符变换原理

Scheduler线程变换原理

整体变换compose和transformer原理

android开发学习知识点

发表于 2018-10-02 | 分类于 移动开发

image

Gradle3.0自动化项目构建技术

发表于 2018-10-02 | 分类于 Java

Groovy快速入门

领域特定语言DSL(Domain Specific Language):其核心思想为"求专不求全,解决特定问题",

Groovy: http://www.groovy-lang.org/
Groovy:是一种基于JVM的敏捷开发语言,结合了Python、Ruby等脚本语言的许多强大特性,可以与Java完美结合,使用Java的所有库;

  1. 语法上支持动态类型,闭包等新一代语言特性
  2. 无缝继承所有Java的库(可以完全用Java写,但是不推荐)
  3. 即支持面向对象编程,也支持面向过程编程

优势:一种更加敏捷的编程语言;入门非常容易,但是功能非常强大;既可以作为编程语言也可以作为脚本语言;熟练掌握Java的人会非常容易掌握Groovy

Groovy开发环境搭建:

java平台上有各种语言的翻版,例如kotlin对c#,scala对haskell,Clojure对lisp,groovy对ruby

macOS/Linux

  1. 安装配置好JDK
  2. 下载Groovy SDK并解压到合适未知
  3. 配置bin目录到/.bash_profile中,如添加如下内容到/.bash_profile
1
export PATH=$PATH:/usr/groovy-2.5.5/bin
  1. groovy -version

InteliJ IDEA配置

  1. 确保已安装Groovy插件
  2. 配置Groovy SDK未知
    image
  3. 编写Groovy版本HelloWorld,注意查看编译后文件
1
2
3
4
5
6
//Java版本
class Test {
public static void main(String[] args){
System.out.println("Hello world");
}
}
1
2
//Groovy版本
print "Hello world"

Groovy基础语法

  1. 变量
  • 变量的类型:基本类型+对象类型,Groovy中没有基本类型,所有的基本类型都会被编译器包装成对象类型,如:int->Integer
  • 变量的定义:强类型定义方式+弱类型def定义方式,Groovy中如果变量的值可以推断除其类型,则可通过def声明为弱类型,区别于java中的强类型定义方式,如:int i=1;
  • 推荐在自有使用模块使用def方式定义,如果有其他模块或其他类使用推荐强类型定义方式
  1. 字符串:String + GString
    String的使用和Java中一致,GString定义方式如下:
  • def name = ‘Hello name’ //不支持可扩展字符串
  • def doubleName = “Hello doubleName” //可扩展字符串,如:def doubleName = “Hello doubleName and ${name}”,结果为: Hello doubleName and Hello name,此时doubleName是org.codehaus.groovy.runtime.GStringImpl的子类
  • def thupleName = ‘’‘Hello thupleName’’’ //支持多行方式

无可扩展字符串时以上3种方式的String都是java.lang.String的子类,编码过程中String和GString是可以通用的,更多从方便使用角度考虑即可

Groovy字符串方法介绍

  • java中String原有的方法
  • DefalutGroovyMethods
  • StringGroovyMethods:普通类型的参数+闭包类型的参数
1
2
3
4
5
6
7
8
9
10
def str = "Groovy",str2 = "Hello",str3= "Hello minus"
//字符串填充:center(),paddingLeft(),paddingRight()
println str.center(8,'a') //aGroovya
//字符串比较:类似于数字比较;compareTo()
println str > str2 //false
//获取字符串索引:类似于数组下标;charAt()
println str[0..1] //Gr
//减法运算:类似于数字减法;minus()
println str3.minus(str2) // minus
//其他方法自己摸索

逻辑控制:单步顺序执行|if/else|switch-case|while|for,基本和Java操作一致,针对Groovy扩展介绍如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//switch-case
def x=1.23,result
switch(x){ //switch(x.class)
case "name":
result = "name"
break
case Integer:
result = "Integer"
break
case BigDecimal:
result = "BigDecimal"
break
case [1,2,3]: //列表
result = "list"
break
case 1..10: //范围
result = "range"
default:
result="defalut"
}
println result //BigDecimal

for循环控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//对范围的for循环
def sum =0
for(i in 0..9){
sum += i
}
println sum //45
//对list的for循环
for(i in [1,2,3,4,5]){
sum += i
}
//对map的for循环
for(i in ["lili":1,"lucy":2]){
println i.key + ":" +i.value
}
  1. 闭包
  • 闭包就是一个代码块,所以需要通过{}括起来,def clouser = { println “Hello Groovy!”};clouser.call();clouser(); //推荐call()方式调用来区分是闭包
  • def clouser = {String name -> println “Hello Groovy ${name}!”};clouser.call(“a”);clouser(“b”);
  • 隐式参数it:def clouser = {println “Hello Groovy ${it}!”};clouser.call(“a”);clouser(“b”);
  • 闭包返回值:总是有返回值的,当闭包体没有明确返回值的时候,返回结果就是null
  • 如果最后一个参数是闭包,闭包可以写在外面

闭包的使用

  • 与基本类型的结合使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int fab1(int number){
int result = 1
1.upto(number,{num -> result *= num })
return result
}

int fab2(int number){
int result = 1
number.downto(1) {
num -> result *= num
}
return result
}

int cal(int number){
int result = 0
number.times {
num -> result += num
}
return result
}
  • 与String结合使用
1
2
3
4
5
6
def str = "the 2 and 3 is 5"
str.each {String tmp -> print tmp.multiply(2)} //tthhee 22 aanndd 33 iiss 55
println str.find {String tmp -> tmp.isNumber()} //2
println str.any {String tmp -> tmp.isNumber()} //true
println str.every {String tmp -> tmp.isNumber()} //false
def list = str.collect {it.toUpperCase()};println list.toListString() //[T, H, E, , 2, , A, N, D, , 3, , I, S, , 5]
  • 与数据结构结合使用
  • 与文件等结合使用
  • 闭包进阶:闭包关键字(this,owner,delegate)+闭包委托策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def scriptClosure = {
println "scriptClosure this:"+this //代表闭包定义处的类
println "scriptClosure owner:"+owner //代表闭包定义处的类或对象
println "scriptClosure delegate:"+delegate //代表任意对象,默认值为owner
}
scriptClosure.call()

//scriptClosure this:Test@3c130745
//scriptClosure owner:Test@3c130745
//scriptClosure delegate:Test@3c130745

class Person{
def static classClosure = {
println "classClosure this:"+this
println "classClosure owner:"+owner
println "classClosure delegate:"+delegate
}

def static say(){
def methodClosure = {
println "methodClosure this:"+this
println "methodClosure owner:"+owner
println "methodClosure delegate:"+delegate
}
methodClosure.call()
}
}

//静态方法调用
Person.classClosure()
Person.say()
//全部指向Person类,闭包指向离他最近的封闭类
//classClosure this:class Person
//classClosure owner:class Person
//classClosure delegate:class Person
//methodClosure this:class Person
//methodClosure owner:class Person
//methodClosure delegate:class Person

//修改Person类中方法,取消static限定符调用
Person p = new Person()
p.classClosure()
p.say()
//全部指向Person类对象,闭包指向离他最近的封闭类对象
classClosure this:Person@a9cd3b1
classClosure owner:Person@a9cd3b1
classClosure delegate:Person@a9cd3b1
methodClosure this:Person@a9cd3b1
methodClosure owner:Person@a9cd3b1
methodClosure delegate:Person@a9cd3b1

//嵌套闭包
def outerClosure = {
def innerClosure = {
println "innerClosure this:"+this
println "innerClosure owner:"+owner
println "innerClosure delegate:"+delegate
}
innerClosure.call()
}
outerClosure.call()

//innerClosure this:Test@3c130745
//innerClosure owner:Test$_run_closure7@9353778 //指向outerClosure
//innerClosure delegate:Test$_run_closure7@9353778

总结:this、owner、delegate的值在大多数情况都是一样的,在嵌套闭包中this的值和owner、delegate的值不一致,只有在给delegate赋值后owner和delegate的值才不一致

闭包的委托策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student{
String name
def sayName = { "My name is ${name}"}
String toString(){
sayName.call()
}
}

class Teacher{
String name
}

def stu = new Student(name: "XingFeng")
println stu.toString()

def tea = new Teacher(name: "Lily")
stu.sayName.delegate = tea
println stu.toString()
stu.sayName.resolveStrategy = Closure.DELEGATE_FIRST //先从delegate中查找name属性,没有了再从owner中查找
println stu.toString()

//My name is XingFeng
//My name is XingFeng
//My name is Lily
  1. 数据结构
    列表的定义:def list = [1,2,3,4] 此为一个ArrayList;
    数组的定义:def list = [1,2,3,4] as int[]; int[] arr=[1,2,3]
    列表的排序:def list = [1,12,3,444]; Collections.sort(list);list.sort()

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
2
3
4
switch(number){
case 0..<60
...
}
  1. 面向对象
    类、接口等的定义和使用
  • Groovy中默认类、方法等都是public类型
  • Groovy中无论是直接调用属性还是通过get/set方法其实质都是通过getter/setter方法调用的属性,getter/setter方法默认自动继承
  • 接口实现需实现接口的所有方法;trait中可以有默认方法实现,没有实现的方法需添加abstract关键字,实现时只需实现abstract的方法即可

元编程(Metaprogramming)是指某类计算机程序的编写,这类计算机程序编写或者操纵其他程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作。很多情况下与手工编写全部代码相比工作效率更高。编写元程序的语言称之为元语言,被操作的语言称之为目标语言。一门语言同时也是自身的元语言的能力称之为反射

元编程通常有两种方式起作用。一种方式是通过应用程序接口(API)来暴露运行时引擎的内部信息。另一种方法是动态执行包含编程命令的字符串。因此,“程序能编写程序”。虽然两种方法都能用,但大多数方法主要靠其中一种。

image

1
2
3
4
5
6
7
8
9
10
11
12
class Baby {
def invokeMethod(String name,Object args){
return "the method is ${name},the args is ${args}"
}

def methodMissing(String name,Object args){
return "the method ${name} is missing}"
}
}

def baby = new Baby()
println baby.cry()

结合上图理解:Java中对象方法的调用没有上图否流程分支,在Groovy中对象方法调用有否分支调用,上例中通过注释invokeMethod、methodMissing方法查看运行效果,通过以下代码可动态添加对象属性和方法:

1
2
3
Baby.metaClass.sex = "male"
Baby.metaClass.play = { ... }
Baby.metaClass.static.play = { ... } //静态方法

通过ExpandoMetaClass.enableGlobally()设置让动态添加方法全局启用

  1. Json操作
  • 对象转换成JSON字符串:JsonOutput.toJson()
  • Json格式化打印:JsonOutput.prettyPrint(jsonObject)
  • Json字符串转对象:def jsonSlurper = new JsonSlurper();jsonSlurper.parse()
  1. xml操作
  • Java对xml的处理:DOM文档驱动处理方式+SAX事件驱动处理方式
  • Groovy解析xml数据:def xmlSlurper = new XmlSlurper();def response = xmlSlurper.parse(xml); //response对象可以逐级访问节点,节点的属性添加@符号,如:response.books.@id,也可以通过闭包过滤信息
  • Groovy深度遍历xml:可以通过逐级遍历解析后的response数据,也可通过response.depFirst().find{ …}遍历或 response.’’.find{ …}遍历(’'代表深度遍历)
  • Groovy深度遍历xml:response.books.children().find{…}或response.books.’’.find{…}(’'代表深度遍历)
  • Groovy创建xml数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
'''
<langs type='current' count='3'>
<language flavor='static' version='1.5' />
<language flavor='public' version='2.5' />
</langs>
'''

def sw = new StringWriter()
def xmlBuilder = new MarkupBuilder(sw)
xmlBuilder.langs(type:'current',count:3){
language(flavor:'static',version:'1.5')
language(flavor:'public',version:'2.5')
}
println sw

def langs = new Langs()
xmlBuilder.langs(type:langs.type,count:langs.count){
langs.languages.each {
language(flavor:it.flavor,version:it.version)
}
}
println sw
  1. 文件操作
  • Java文件处理:节点流(InputStream、OutputStream及其子类)+处理流(Reader、Writer及其子类),所有Java对文件的操作Groovy都支持
  • 遍历文件内容:def file = new File(“Test.iml”);file.eachLine { println it } 或 def text = file.getText() 或 def text = file.readLines() …

gradle

Gradle是一款最新的,功能强大的构建工具,使用程序代替传统的xml配置,项目构建更加灵活,有丰富的第三方库

gradle组成:groovy核心语法+build script block+gradle api

gradle生命周期

执行./gradlew clean 观察执行过程,其生命周期包括:初始化、配置、执行
image

gradle生命周期的监听

在项目的build.gradle中添加如下

1
2
3
4
5
6
7
8
//在配置阶段开始之前的回调
this.beforeEvaluate {}

//配置阶段完成以后的回调
this.afterEvaluate {}

//gradle生命周期执行完以后的回调
this.gradle.buildFinished {}

Gradle Project

./gradlew projects //查看工程Project数量,学会区分Project与module及根Project与子Project,每个Project必须有一个build.gradle文件

Project API组成:

  1. Project相关API:如何管理父Project及如何操作子Project
  • this.getAllProjects(),this.getSubProjects(),this.getParent(),在gradl文件中,对应allprojects、project、subprojects进行操作

./gradlew projects可实现显示所有项目,自我实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def getProjects(){
println "------------------------"
this.getAllprojects().eachWithIndex{ Project project, int index ->
if(index == 0){
println "Root project:${project.name}"
}else{
println "+--- project:${project.name}"
}
}
}

this.getProjects()

//------------------------
//Root project:MyApplication
//+--- project:app
  1. task相关API

  2. 属性相关API

  • 父Project的属性在子项目中会被继承,可直接使用
  • 可以在项目中通过common.gradle文件来定义扩展属性ext,然后在根Project中通过apply from:this.file(‘common.gradle’)引入后,按rootProject.ext.定义属性的方式使用
  • 在gradle.properties中定义key-value属性,如:isLoadTest=false,然后在settings.gradle中就可以编码控制是否加载Test项目
1
2
3
if(hasProperty('isLoadTest')? isLoadTest.toBoolean() : false){
include ':Test'
}

自定义属性的两种方式:ext方式+gradle.properties中定义
4. file相关API

  • 路径获取API:getRootdir()、getBuildDir()、getProjectDir()
  • 文件操作相关API:都是基于根工程操作的,不支持跨工程操作
1
2
3
4
5
6
7
8
9
//文件/文件夹拷贝
copy {
from file('test.txt')
into getRootProject().getBuildDir()
}
//文件树遍历
fileTree('build/'){
FileTree fileTree -> fileTree.visit{ FileTreeElement element -> ... }
}
  1. gradle生命周期API

  2. 其他API

  • 依赖相关API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
//等价于以下操作:
buildscript { ScriptHandler scriptHandler ->
scriptHandler.repositories { RepositoryHandler repositoryHandler ->
repositoryHandler.google()
repositoryHandler.jcenter()
}
scriptHandler.dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}

依赖传递:A模块依赖B模块,B模块依赖C模块,如果A模块也需要C模块功能,不需依赖使用,防止B修改后去掉C依赖而导致错误,可在A中引入C模块,通过exclude排除依赖,transitive禁止依赖传递

占位编译provided:A.类库只在编译阶段起作用 B.父项目已引入类库,子项目直接使用父项目类库,但为了子项目编译通过使用占位编译

  • 外部命令执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
task abc() {
doLast{
def command = 'ls'
exec{
try{
executable 'bash'
args '-c',command
println 'command is execute success.'
}catch(GradleException ex){
println "Excepiotn...."
}
}
}
}

执行:./gradlew abc

Task

  1. Task定义及配置
    直接通过task函数去创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
task("abcd") {
doLast{
def command = 'ls -al'
exec{
try{
executable 'bash'
args '-c',command
println 'command is execute success.'
}catch(GradleException ex){
println "Excepiotn...."
}
}
}
}

通过TaskContainer创建

1
2
3
this.tasks.create("aa"){
println 'Hello task'
}

Task创建之后可在开发工具的gradle插件重查找到task,如果没有设置group,则默认在other分组中,更多配置可通过task源码查看
2. Task执行详解
doFirst/doLast执行阶段执行,否则在配置阶段执行

1
2
3
4
5
6
7
8
9
10
11
task aa{
doFirst{
println 'Hello 2'
}
}
task.doFirst{
println 'Hello 1'
}

//Hello 1
//Hello 2

编写一个统计build时长的task
app.gradle中编写:

1
2
3
4
5
6
7
8
9
10
11
12
13
def startBuilderTime,endBuilderTime
this.afterEvaluate { Project project ->
def preBuildTask = this.tasks.getByName("preBuild")
preBuildTask.doFirst {
startBuilderTime = System.currentTimeMillis()
println '------开始计时...'
}
def buildTask = this.tasks.getByName("build")
buildTask.doLast {
endBuilderTime = System.currentTimeMillis()
println '------计时结束,耗时:'+(endBuilderTime - startBuilderTime)
}
}

./gradlew build执行查看结果
3. Task的依赖及执行顺序

  • dependsOn强依赖方式
1
2
3
4
5
6
7
8
9
10
11
12
13
task t1() { doLast{println 'task t1'} }
task t2() << { println 'task t2' } //此处"<<"等同于doLast
task t3(dependsOn:[t1,t2]) { doLast{println 'task t3'} }
task t4() { dependsOn this.tasks.findAll { task -> return task.name.equals("t2")};doLast{println 'task t4'} }

//./gradlew t3: (t1和t2执行顺序是随机的)
//task t1
//task t2
//task t3

//./gradlew t4
//task t2
//task t4
  • 通过Task输入输出指定
    TaskInputs:参数为任意对象及文件、文件夹;TaskOutputs:只输出文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
ext{
println '------配置中...'
versionCode = 100
versionName = "V2.0.0"
versionInfo = "第一个版本"
destFile = file("release.xml")
if(destFile != null && !destFile.exists()){
destFile.createNewFile()
}
}

class VersionMsg{
Integer versionCode
String versionName
String versionInfo
}

task writerTask{
//为task指定输入
inputs.property("versionCode",this.versionCode)
inputs.property("versionName",this.versionName)
inputs.property("versionInfo",this.versionInfo)
//为task指定输出
outputs.file destFile

doLast{
def data = inputs.getProperties()
File file = outputs.getFiles().getSingleFile()
def versionMsg = new VersionMsg(data)
def sw = new StringWriter()
def xmlBuilder = new groovy.xml.MarkupBuilder(sw)
if(file.text != null && file.text.size() <=0){
xmlBuilder.releases{
release{
versionCode(versionMsg.versionCode)
versionName(versionMsg.versionName)
versionInfo(versionMsg.versionInfo)
}
}
file.withWriter { writer ->
writer.append(sw.toString())
}
}else{
def lines = file.readLines()
def lengths = lines.size() - 1
file.withWriter { writer ->
lines.eachWithIndex{ String line, int index ->
if(index != lengths){
writer.append(line +"\r\n")
}else if(index == lengths){
writer.append("\r\n" + sw.toString()+"\r\n")
writer.append(lines.get(lengths))
}
}
}

}
}
}

task readTask{
inputs.file destFile
doLast{
def file = inputs.files.singleFile
println file.text
}
}

task taskTest{
dependsOn readTask,writerTask
doLast{
println "输入输出任务结束"
}
}

destFile作为writerTask输出结果输入到readTask

  • 通过API指定执行顺序:mustRunAfter/shouldRunAfter
1
2
task t1() { doLast{println 'task t1'} }
task t2() { mustRunAfter t1 doLast {println 'task t2'} }

通过./gradlew t2 t1查看执行结果
4. Task类型
详见官方文档:https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Delete.html#org.gradle.api.tasks.Delete
5. 构建到生命周期

1
2
3
4
5
6
7
8
this.project.afterEvaluate {project ->
println "开始挂接..."
def buildTask = project.tasks.getByName("build")
if(buildTask == null) throw GradleException("build Task not found")
buildTask.doLast {
writerTask.execute()
}
}

Gradle其他模块

  1. Settings类:对应Settings.gradle
1
2
3
if(hasProperty('isLoadTest')? isLoadTest.toBoolean() : false){
include ':Test'
}
  1. SourceSet类:AndroidSourceSet/JavaSourceSet,决定了代码、资源、第三方库要存放的位置
1
2
3
4
5
6
7
8
9
//修改.so等jnilibs的存放位置
android{
sourceSets {
main{
jniLibs.srcDirs = ['libs']
res.srcDirs = ['src/main/res','src/main/res-ad'] //对res文件夹内容进行分类,但是只能在Project视图查看到效果
}
}
}
  1. Gradle的Plugin
  • Gradle没有提供创建自定义Gradle插件工程的模板,需要开发者手动创建Gradle插件工程
  • 使用Groovy开发,其Gradle插件工程必须遵循如下的目录结构:
    groovy代码必须位于xxxProject/src/main/groovy/目录下
    提供插件属性声明文件,该文件必须位于xxxProject/src/main/resources/META-INF/gradle-plugins/xxx.properties
  1. android插件对gradle的扩展
    android具体能配置那些属性,可查看源码通过BaseExtension查看

gradle插件: https://avatarqing.gitbooks.io/gradlepluginuserguidechineseverision/content/introduction/README.html

varints变体

Cordova入门

发表于 2018-10-02 | 分类于 移动开发
1
2
3
* 官网网站:http://cordova.apache.org/
* 中文文档:http://cordova.axuer.com/docs/zh-cn/latest/guide/overview/index.html
* 英文文档:http://cordova.apache.org/docs/en/latest/

概述

Apache Cordova是一个开源的移动开发框架。允许你用标准的web技术-HTML5,CSS3和JavaScript做跨平台开发。 应用在每个平台的具体执行被封装了起来,并依靠符合标准的API绑定去访问每个设备的功能,比如说:传感器、数据、网络状态等

架构

image

  • WebView:Cordova启用的WebView可以给应用提供完整用户访问界面。在一些平台中,他也可以作为一个组件给大的、混合应用,这些应用混合和Webview和原生的应用组件
  • Web App:这是你应用程序代码存在的地方。应用的实现是通过web页面,默认的本地文件名称是是index.html,这个本地文件应用CSS,JavaScript,图片,媒体文件和其他运行需要的资源。应用执行在原生应用包装的WebView中,这个原生应用是你分发到app stores中的;这个容器中包含一个非常重要文件- config.xml 文件他提供App的重要的信息和特定的参数用来影响App的工作
  • 插件:提供了Cordova和原生组件相互通信的接口并绑定到了标准的设备API上。这使你能够通过JavaScript调用原生代码.

注意:当你创建一个Cordova项目它不存在任何插件。这是新的默认行为。任何你需要的组件,哪怕是核心组件,你也必须明确添加。

  • 开发工作流:Cordova提供两个基本的工作流用来创建移动App.
  1. 跨平台(CLI)的工作流:如果你想你的App运行在尽可能多的移动操作系统,那么就使用这个工作流,你只需要很少的特定平台开发。这个工作流围绕这’cordova’CLI(命令行)。CLI把公用的web资源复制到每个移动平台的子目录,根据每个平台做必要的配置变化,运行构建脚本生成2进制文件。一般都是使用这种方式。
  2. 平台为中心的工作流:如果你专注于构建单独平台的App或者需要需要在底层修改它那么就使用这个工作流吧。

创建第一个App

安装Cordova CLI

  • 下载和安装Node.js。安装完成后你可以在命令行中使用node 和 npm
  • mac上xcode开发环境已OK
  • mac上Android开发环境已OK,且Android的全局变量已配置,如:ANDROID_HOME
1
2
export ANDROID_HOME=/Users/Neel/Documents/Softwares/adt-bundle-mac-x86_64-20140321/sdk
export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
  • sudo npm install -g cordova //-g标志是告诉 npm 我们全局安装 cordova
  • 命令行输入cordova,检验是否安装成功
1
2
3
4
5
6
7
8
9
10
11
12
CLI命令概要

Help:显示可用CLI命令的信息。
Create:创建Cordova项目并关联项目文件夹和文件。
Plateform:管理Cordova项目使用的移动平台。
Plugin:管理Cordova插件的安装和卸载。
Prepare:从Cordova项目的www文件夹复制web应用内容到项目移动平台项目文件夹中。
Compile:把web应用打包成Cordova应用。
Build:先执行Prepare命令然后打包web应用。
Emulate:在一个或多个移动设备平台的设备模拟器中运行Cordova应用。
Run:在一个或多个移动设备中运行Cordova应用。
Serve:启动一个服务器加载web内容以便于用浏览器访问

创建App

  • 方法一:cordova create hello com.example.hello HelloWorld
  • 方法二:webstorm创建
  1. webstorm添加cordova支持:Settings → Plugins
  2. webstorm创建项目

添加平台

  1. 检查你当前平台设置状况:cordova platform ls,运行add或者remove平台的命令将会影响项目 platforms的内容,在这个目录中每个指定平台都有一个子目录
  2. 添加Android平台支持:cordova platform add android --save
  3. 添加IOS平台支持:cordova platform add ios --save
  4. 添加浏览器支持:cordova platform add browser --save
  5. npm install ios-sim -g //如果ios环境,可能需要添加这个

构建及测试

  • 安装构建先决条件检查:cordova requirements
  • 构建App:cordova build,构建所有平台;cordova build ios,构建特定平台
  • 测试:模拟器-cordova emulate android;或者可将手机插入电脑,在手机上直接测试-cordova run android
  • 说明:构建和测试也可通过webstorm直接进行

添加插件

App要接触设备级别的特性,就需要你添加插件了.个插件 通过JavascriptAPI暴露原生SDK功能。插件通常由npm分发(http://cordova.axuer.com/plugins/),一些关键的API由Apache Cordova开源项目提供并且这些插件是作为[核心插件API]的.

  • 搜索插件:cordova plugin search camera
  • 查看当前安装的插件:cordova plugin ls
  • 添加插件:cordova plugin add cordova-plugin-camera //plugin要添加camera插件,我们需要指定camera的npm包名
  • 添加插件:cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git

使用 merges自定义每个平台

顶级merges目录提供了特定平台部署特定资源的地方。每个特定平台在merges中的子目录反映了www 源代码树中的结构, 允许你重写和添加文件。

存放各个平台特殊的文件,会和www进行合并编译,相同的文件merges下的文件优先。

比如:

1
2
3
4
5
6
7
merges/ 
|-- ios/
| `-- app.js
|-- android/
| `-- android.js
www/
`-- app.js

编译成iOS应用的话,包含merges/ios/app.js;而Android应用的话,包含www/app.js、merges/android/android.js

hooks目录

存放自定义cordova命令的脚本文件。每个project命令都可以定义before和after的Hook,比如:before_build、after_build。
Hook可以采用任何编程语言来写,Cordova CLI采用的是Node.js,所以一般都是用它来写

更新Cordova和项目

  • 要查找最新的cordova版本:npm info cordova version
  • 查看当前版本:cordova -v
  • 更新到最新版本:sudo npm update -g cordova
  • 安装指定版本:sudo npm install -g cordova@3.1.0-0.2.0
  • 更新目标项目的平台:cordova platform update android --save

平台开发

  • 查看所有支持的模拟器:cordova run --list

Android

  • 要想知道你的Cordova项目中安装的Cordova Android包的版本,你可以在项目目录中运行cordova platform ls
  • 平台搭建过程
  1. 安装Java Development Kit (JDK) 7或者最新的
  2. 安装Android SDK
  3. 添加SDK包:
1
Android API级别查看:http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels

打开Android SDK Manager (例如,在终端上运行`android),并确保下面已经安装:

    • 目标Android版本的Android Platform SDK
    • Android SDK build-tools,版本19.1.0或者之上
    • Android Support Repository (在"Extras"查找)
  1. 设置环境变量
    • 设置JAVA_HOME环境变量,指定为JDK安装路径
    • 设置ANDROID_HOME环境变量,指定为Android SDK安装路径
    • 添加Android SDK的tools和platform-tools目录到你的PATH
  1. Android Studio调试

Cordova的Android项目可以被Android IDEAndroid Studio打开;

如果你想使用Android Studio内置的Android调试/分析工具或者你要开发Android插件这是十分有用的

在Android Studio中打开Cordova的Android项目:

  • 启动 Android Studio.
  • 选择 Import Project (Eclipse ADT, Gradle, etc).
  • 选择你项目中的Android platform目录(/platforms/android)
  • 对于Gradle Sync问题你可以简单的回答 Yes.

==注意==:当在Android studio里打开你的项目,建议你不要编辑你的代码在IDE中。这会在 platforms目录中编辑你的代码(而不是 www),并且变化将会被重写。而是编辑www目录并通过运行cordova build来拷贝过来你的变化。
6. Cordova和Android的生命周期

Cordova事件 粗略的Android等效 含义
deviceready onCreate() 应用程序开始(不是从背景)
pause onPause() 应用程序移动到背景
resume onResume() 应用程序返回到前景

关于生命周期:

在Android设备中,操作系统可以选择在后台杀死活动来释放资源,如果当前设备运行程序的内存过低。由于这个原因,你的应用程序知道生命周期被触发并维持任何确保用户在离开应用程序用户上下文不丢失的状态,是必须的。

应该通过bindEvents 方法来注册应用程序回调来回应生命周期事件来保存状态。保存什么息和怎么保存信息由你决定,但是你要确保保存足够的信息,来精确的恢复到用户离开的地方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 这个状态代表了应用程序的状态并且会在onResume()和onPause()中保存和恢复
var appState = {
takingPicture: true,
imageUri: ""
};

var APP_STORAGE_KEY = "exampleAppState";

var app = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
// 这里我们注册我们关心的生命周期事件回调
document.addEventListener('deviceready', this.onDeviceReady, false);
document.addEventListener('pause', this.onPause, false);
document.addEventListener('resume', this.onResume, false);
},
onDeviceReady: function() {
document.getElementById("take-picture-button").addEventListener("click", function() {
//由于camera插件方法启动了一个外部活动
//这里有一次机会我们的应用程序被kill掉在回调被成功或者失败调用之前
// 在onPause()和onResume()那里我们保存和恢复状态,来处理这个事情
appState.takingPicture = true;

navigator.camera.getPicture(cameraSuccessCallback, cameraFailureCallback,
{
sourceType: Camera.PictureSourceType.CAMERA,
destinationType: Camera.DestinationType.FILE_URI,
targetWidth: 250,
targetHeight: 250
}
);
});
},
onPause: function() {
// 这里我们检测我们是否在获取图片,如果在,我们希望保存我们的状态以便onResume()
// 恢复的时候使用,如果我们获得了图片URI我们也要存储
if(appState.takingPicture || appState.imageUri) {
window.localStorage.setItem(APP_STORAGE_KEY, JSON.stringify(appState));
}
},
onResume: function(event) {
// 这里我们检差存储的状态,如果需要恢复他。由你跟踪任何添加的插件结果的来源
// (也就是说你代码的哪一步被调用),还有什么参数提供给插件如果相关
var storedState = window.localStorage.getItem(APP_STORAGE_KEY);

if(storedState) {
appState = JSON.parse(storedState);
}

// 检查如果我们需要恢复我们的图片
if(!appState.takingPicture && appState.imageUri) {
document.getElementById("get-picture-result").src = appState.imageUri;
}
// 现在我们可以检测如果插件结果在事件对象里面
// 这里需要cordova-android 5.1.0+
else if(appState.takingPicture && event.pendingResult) {
// 检测插件调用是否成功并调用相应的回调。对于camera插件,"OK"
//意味着成功其他意味着错误
if(event.pendingResult.pluginStatus === "OK") {
// camera放置同样的结果在resume对象,因为成功回调传递给了getPicture(),
// 因此我们可以传递同样的回调,返回一些其他东西。查询文档,了解怎么解释你使用
// 插件的结果字段
cameraSuccessCallback(event.pendingResult.result);
} else {
cameraFailureCallback(event.pendingResult.result);
}
}
}
}

// 这里是回调我们传入getPicture()
function cameraSuccessCallback(imageUri) {
appState.takingPicture = false;
appState.imageUri = imageUri;
document.getElementById("get-picture-result").src = imageUri;
}

function cameraFailureCallback(error) {
appState.takingPicture = false;
console.log(error);
}

app.initialize();

自定义图标(Icon)

对启动画面(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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<platform name="android">
<!--
ldpi : 36x36 px
mdpi : 48x48 px
hdpi : 72x72 px
xhdpi : 96x96 px
xxhdpi : 144x144 px
xxxhdpi : 192x192 px
-->
<icon src="res/android/ldpi.png" density="ldpi" />
<icon src="res/android/mdpi.png" density="mdpi" />
<icon src="res/android/hdpi.png" density="hdpi" />
<icon src="res/android/xhdpi.png" density="xhdpi" />
<icon src="res/android/xxhdpi.png" density="xxhdpi" />
<icon src="res/android/xxxhdpi.png" density="xxxhdpi" />
</platform>

IOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<platform name="ios">
<!-- iOS 8.0+ -->
<!-- iPhone 6 Plus -->
<icon src="res/ios/icon-60@3x.png" width="180" height="180" />
<!-- iOS 7.0+ -->
<!-- iPhone / iPod Touch -->
<icon src="res/ios/icon-60.png" width="60" height="60" />
<icon src="res/ios/icon-60@2x.png" width="120" height="120" />
<!-- iPad -->
<icon src="res/ios/icon-76.png" width="76" height="76" />
<icon src="res/ios/icon-76@2x.png" width="152" height="152" />
<!-- iOS 6.1 -->
<!-- Spotlight Icon -->
<icon src="res/ios/icon-40.png" width="40" height="40" />
<icon src="res/ios/icon-40@2x.png" width="80" height="80" />
<!-- iPhone / iPod Touch -->
<icon src="res/ios/icon.png" width="57" height="57" />
<icon src="res/ios/icon@2x.png" width="114" height="114" />
<!-- iPad -->
<icon src="res/ios/icon-72.png" width="72" height="72" />
<icon src="res/ios/icon-72@2x.png" width="144" height="144" />
<!-- iPhone Spotlight and Settings Icon -->
<icon src="res/ios/icon-small.png" width="29" height="29" />
<icon src="res/ios/icon-small@2x.png" width="58" height="58" />
<!-- iPad Spotlight and Settings Icon -->
<icon src="res/ios/icon-50.png" width="50" height="50" />
<icon src="res/ios/icon-50@2x.png" width="100" height="100" />
</platform>

存储数据

LocalStorage

LocalStorage提供了简单和同步的键值对存储方式,而且在各个Cordova平台,底层的WebView实现都支持它。

LocalStorage可以通过window.localStorage访问到。以下的代码片段展示了返回的storage对象的最重要的几个方法。

1
2
3
4
var storage = window.localStorage;
var value = storage.getItem(key); // 传递键的名字获取对应的值。
storage.setItem(key, value) // 传递键的名字和对应的值去添加或者更新这个键值对。
storage.removeItem(key) // 传递键的名字去从LocalStorage里删除这个键值对。

SQLite 插件

  • cordova-sqlite-storage - 包含sqlite3实现的核心版本,它支持iOS, Android和Windows平台。
  • cordova-sqlite-ext - 包含Android和iOS的正则支持等额外特性的扩展版本。
  • cordova-sqlite-evfree - 与cordova-sqlite-ext类似,但提供了高级的内存管理。GPL版本低于v3或者有商业许可的话可用。

安全管理建议

  • 使用app内置浏览器打开外链:因为app内置浏览器会使用原生浏览器的安全特性,而且不会让你的Cordova环境被外部访问到
  • 校验所有的用户输入,服务端同样需要验证输入,特别是在传递数据到后台服务之前。
  • 不要缓存敏感信息
  • 不要使用eval()除非你知道你自己正在做什么

白名单

外部域是应用无法控制的,而域名白名单则是一种控制访问外部域的安全模型。Cordova提供了一项可配置的安全策略来定义哪些外部站点可以访问。默认情况下,新的app被配置成可以访问任何站点。然而在发布到生产环境前,你应该制定一份白名单,限制应用可以访问的域名和子域名。

对于Android

可以使用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 当用户按下增加声音按钮事件触发

参考

config.xml

http://cordova.axuer.com/docs/zh-cn/latest/config_ref/index.html

问题解决:

https://forum.ionicframework.com/t/ionic-3-ionic-serve-error-cannot-read-property-filter-of-undefined/85682/11

http://ionicframework.com/docs/components/#overview

http://www.runoob.com/ionic/ionic-tutorial.html

https://creator.ionic.io/app/dashboard/projects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ionic run ios --device
ionic run ios --emulator
ionic run ios --target="iPhone-5s"
ionic run ios --target="iPhone-6"
ionic run ios --target="iPhone-6s"
ionic run ios --emulator --target="iPhone-6s" -l


http://localhost:8100/

ios-sim showdevicetypes

cordova run ios --target "iPad-Pro" --emulator

xcrun simctl list devices

ios-sim命令行工具。

ios-sim 是一个可以在命令控制iOS模拟器的工具。利用这个命令,我们可以启动一个模拟器,安装app,启动app,查询iOS SDK。它可以使我们像自动化测试一样不用打开Xcode。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Usage: ios-sim <command></command> <options> [--args ...]

Commands:
showsdks List the available iOS SDK versions
showdevicetypes List the available device types
launch <application path> Launch the application at the specified path on the iOS Simulator
start Launch iOS Simulator without an app
install <application path> Install the application at the specified path on the iOS Simulator without launching the app

Options:
--version Print the version of ios-sim
--help Show this help text
--exit Exit after startup
--log <log file path> The path where log of the app running in the Simulator will be redirected to
--devicetypeid <device type> The id of the device type that should be simulated (Xcode6+). Use 'showdevicetypes' to list devices.
e.g "com.apple.CoreSimulator.SimDeviceType.Resizable-iPhone6, 8.0"

Removed in version 4.x:
--stdout <stdout file path> The path where stdout of the simulator will be redirected to (defaults to stdout of ios-sim)
--stderr <stderr file path> The path where stderr of the simulator will be redirected to (defaults to stderr of ios-sim)
--sdk <sdkversion> The iOS SDK version to run the application on (defaults to the latest)
--family <device family> The device type that should be simulated (defaults to `iphone')
--retina Start a retina device
--tall In combination with --retina flag, start the tall version of the retina device (e.g. iPhone 5 (4-inch))
--64bit In combination with --retina flag and the --tall flag, start the 64bit version of the tall retina device (e.g. iPhone 5S (4-inch 64bit))

Unimplemented in this version:
--verbose Set the output level to verbose
--timeout <seconds> The timeout time to wait for a response from the Simulator. Default value: 30 seconds
--args <...> All following arguments will be passed on to the application
--env <environment file path> A plist file containing environment key-value pairs that should be set
--setenv NAME=VALUE Set an environment variable</environment file path></seconds></device family></sdkversion></stderr file path></stdout file path></device type></log file path></application path></application path></options>

ios-sim launch /Users/YDZ/Desktop/app.app --devicetypeid iPhone-6s
其中,/Users/YDZ/Desktop/app.app这个是设计师收到app之后的路径。–devicetypeid参数后面是给定一个模拟器的版本。

只需要把上面的命令发给设计师,无脑粘贴到命令行,装好app的模拟器就会自动启动,打开app了。

大公司的话可以应该有两个账号,一个上appstore的开发账户,这个严格保密。还有一个打线下包的企业账号,这样就能达到需求了

RPC、http与Restful

发表于 2013-03-24 | 分类于 java

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
2
3
4
GET /rest/api/getDogs --> GET /rest/api/dogs 获取所有小狗狗 
GET /rest/api/addDogs --> POST /rest/api/dogs 添加一个小狗狗
GET /rest/api/editDogs/:dog_id --> PUT /rest/api/dogs/:dog_id 修改一个小狗狗
GET /rest/api/deleteDogs/:dog_id --> DELETE /rest/api/dogs/:dog_id 删除一个小狗狗

一个完整的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架构分为三部分:

  1. 服务提供者,运行在服务器端,提供服务接口定义与服务实现类。
    
  2. 服务中心,运行在服务器端,负责将本地服务发布成远程服务,管理远程服务,提供给服务消费者使用。
    
  3. 服务消费者,运行在客户端,通过远程代理对象调用远程服务。
    

未命名

发表于 2009-06-25
域名系统 (DNS)

域名系统 (DNS)

组织到域层次结构中的命名计算机和网络服务的系统。DNS 用于在 TCP/IP 网络中通过友好的名称定位计算机。DNS 将友好的名称解析计算机能理解的 IP 地址。

在 Oracle Net 中,DNS 把 TCP/IP 地址中使用的主机名翻译成 IP 地址。

相关主题

Oracle Net Services 概览

版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。

未命名

发表于 2009-06-25
一般信息:高级

一般信息:高级

高级选项卡使您能够为客户机或服务器的计算机配置高级概要文件信息。

发送操作超时

用于指定数据库服务器在与客户机建立连接后,完成“向客户机发送”操作的时间 (以秒计)。

建议在客户机出现偶然或异常关闭的环境中设置此参数。如果数据库服务器无法在指定时间内完成发送操作,该服务器将向 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 能够使用由基础协议提供的紧急数据发送或接收“中断”消息。

如果选择此选项,将禁用使用由基础协议提供的紧急数据发送或接收“中断”消息的功能。一旦启用,此功能将应用到此客户机使用的所有协议中。

相关主题

配置高级概要文件信息

Oracle Net Services 概览  

版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。

未命名

发表于 2009-06-25
一般信息:访问权限

一般信息:访问权限

访问权限选项卡使您能够指定允许或拒绝哪些客户机访问数据库。

检查 TCP/IP 客户机访问权限

如果要指定哪些客户机允许和拒绝访问数据库,请选中该复选框。如果要禁用该功能,请取消选中该复选框。如果取消选中该复选框,则允许所有客户机进行访问。

拒绝访问的客户机

输入主机名或 IP 地址来指定拒绝哪些客户机访问数据库。使用逗号分隔同一行中的条目。

允许访问的客户机

输入主机名或 IP 地址来指定允许哪些客户机访问数据库。使用逗号分隔同一行中的条目。

注:允许访问的客户机优先于拒绝访问的客户机。

相关主题

Oracle Net Services 概览

版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。

未命名

发表于 2009-06-25
一般信息:事件记录

一般信息:事件记录

事件记录选项卡使您能够设置本计算机上的事件记录参数。如果本计算机是客户机,请使用客户机信息字段。如果本计算机是服务器,请使用服务器信息字段。

日志目录

输入日志文件将写入的目录路径。默认值为 $ORACLE_HOME/network/log (在 UNIX 上) 和 ORACLE_HOME \network\log (在 Windows 平台上)。

日志文件

输入客户机上日志文件的名称。默认名称为 sqlnet.log。

相关主题

配置概要文件事件记录和跟踪

Oracle Net Services 概览

版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。

未命名

发表于 2009-06-25
一般参数:验证

一般参数:验证

使用验证选项卡可以配置监听程序的安全性。如果进行了配置,从监听程序控制实用程序发布的授权操作 (如保存配置更改或停止监听程序) 将需要口令。Oracle Net Manager 使您能够设置加密口令。

不需要监听程序操作口令

选择此选项以禁用管理员任务的验证。

需要监听程序操作口令

选择此选项以启用某些管理员任务的验证。然后输入所需口令。默认口令是“oracle”。

注:Oracle Net 允许为每个监听程序配置一个口令。

相关主题

配置监听程序的口令验证

Oracle Net Services 概览

版权所有 © 1996,2009,Oracle 和/或其子公司。保留所有权利。
Oracle 是 Oracle Corporation 和/或其子公司的注册商标。
其他名称可能是其各自所有者的商标。

1…151617…50
行锋

行锋

496 日志
15 分类
74 标签
GitHub E-Mail
自古写字楼如青楼,不许楼里见白头
© 2015 — 2019 行锋
博客全站共229.9k字