不奢望岁月静好 只希望点滴积累

0%

Java内存模型

基本概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 线程通信
线程之间以何种方式进行消息传递
共享内存 & 消息传递

2. 线程同步
程序间用于控制不同线程间操作发生相对顺序的机制

java是共享内存模型】采用的是隐式通信、显式修改

jvm定义了线程和主内存(Main Memory)之间的关系:
1) 线程之间的共享变量存储在主内存中
2) 线程私有变量存储在私有本地内存 Local Memory中、
本地内存是jvm的一个抽象概念、并非真实存在、涵盖缓存、缓冲区、寄存器及其它硬件及编译器优化
Java同步原语(synchronize volatile final)

指令重排

1
2
3
4
5
6
7
8
1. 编译器重排
在不改变单线程语义的条件下、编译器可以重排指令的执行顺序
2. 指令重排
现代cpu采用了指令级并行技术、可以同时执行多条指令、若无数据依赖、
处理器可以改变机器指令的执行顺序
3. 内存系统的重排
由于处理器采用缓存和读写缓冲区、使得加载和存储操作看上去是乱序的、
可能在乱序执行

jvm 指令执行

1
2
3
4
未使用同步的程序在jvm中的执行基本无序、
1. jvm不保证单线程内的操作会按照程序代码顺序执行、临界区指令重排
2. jvm不保证所有线程看到的执行顺序一致
3. jvm不保证64位的long、double类型写操作具有原子性

下载

1
http://archive.apache.org/dist/lucene/solr/

安装配置

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
1. 将下载完成的solr解压到tomcat的指定目录中
eg. 我下载的是 tomcat-7.2.1.zip、
解压目录是 ~/Downloads/solr-7.2.1
tomcat部署目录是 ~/www/Java

2. 复制solr-7.2.1/server/solr-webapp/webapp到tomcat部署目录、同时重命名
(重命名为非必要步骤、为了方便理解)、
要copy的目录是 solr-7.2.1/server/solr-webapp/webapp/、不是 solr-7.2.1/server/solr-webapp/、注意别cp错了~
cp -R solr-7.2.1/server/solr-webapp/webapp/ ~/www/Java/solr

3. 相关jar包复制
1)solr-7.2.1/server/lib/ext下所有jar
2) solr-7.2.1/server/lib/metrics*相关的jar
3) solr-7.2.1/dist/solr-dataimporthandler*.jar

[当前处于~/Downloads下]
cp -R solr-7.2.1/server/lib/ext/ ~/www/Java/solr/WEB-INF/lib/
cp -R solr-7.2.1/dist/solr-dataimporthandler-* ~/www/Java/solr/WEB-INF/lib/
cp -R solr-7.2.1/server/lib/metrics-* ~/www/Java/solr/WEB-INF/lib/

4. 在 ~/www/Java/solr/WEB-INF/ 下创建文件夹 classes 用来存放日志配置文件
mkdir ~/www/Java/solr/WEB-INF/classes

5. 将日志配置文件放入
cp ~/Downloads/solr-7.2.1/server/resources/log4j.properties ~/www/Java/solr/WEB-INF/classes/

6. 创建solr_home目录、作为solr的运行目录
(eg. solr创建的score会放在这里)
mkdir ~/www/Java/solr_home

7. 修改配置、将solr_home指定为刚刚创建的位置
vi ~/www/Java/solr/WEB-INF/web.xml

两处修改:
1) env-entry 的注释打开、并且将
<env-entry-value>。。。</env-entry-value>修改为刚才创建的目录
<env-entry-value>/Users/nj/www/Java/solr_home</env-entry-value>
2) <security-constraint>注释掉(配置访问权限、不然有可能会403)、

env.png
security.png

启动solr

1
2
3
4
重启tomcat
cd ~/build/java/apache-tomcat/bin
sh shutdown.sh
sh startup.sh

访问

1
2
3
4
访问 localhost:8081/solr/index.html 可以看到solr的管理界面
注:
1. 端口号是自己的tomcat的访问端口、可能是8080或者其它任意端口
2. 访问时一定加上 index.html

image.png

==solr服务搭建end

1
2
这样就搭建完成、可以开始使用了
如果遇到404的情况、可以检查下 使用的jar包是不是都copy完成了

初始化solr数据

1
2
3
4
5
6
7
1. 创建文件夹 ~/www/Java/solr_home/new_core 用来存放core内容
将conf文件cp进去
cp -r ~/www/Java/solr_home/configsets/_default/conf ~/www/Java/solr_home/new_core/
2. 在页面上可以看到 如下图所示、点击添加一个 core
3. image2中填写的部分都可以修改 name和instanceDir要保持一致(同为刚刚建立的文件夹的名字)
4. 创建成功之后、就可以看到 image中、划线的地方变成了、core Selector、点击、可以看到我们刚刚创建的new_core、如image3
自定义core创建完成、

image.png

image2.png

image3.png

导入数据

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
1. 引入jar包
cp ~/www/Java/lib/mysql/mysql-connector-java-5.1.38.jar ~/www/Java/solr/WEB-INF/lib/
2. 复制solr-7.2.1/example/example-DIH/solr/db/conf/下的db-data-config.xml到solr-home/core2/conf/下,此处改名为data-config.xml(也可以不修改)
3. 修改配置内容
<dataConfig>
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/taotao" user="root" password="root"/>
<document>
<entity name="tb_item"
query="select id,title,sell_point,price,num,barcore,image,cid,status,created,updated from tb_item">
</entity>
</document>
</dataConfig>

4. 修改solrconfig、添加导入信息
vi ~/www/Java/solr_home/new_core/conf/solrconfig.xml

<!-- add by myself -->
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
注意要和requestHandler标签同级
4. 自定义solr字段、在manager-schema中添加filed字段(放在text后即可)
如:field.png所示
注意:type必须是fileType已定义的类型(defined.png)
5. 数据导入
6. 数据查询(query.png)

data-config.png

solrconfig.png
field.png
defined.png

import.png

query.png

end

1
这样就可以开始使用了^.^

  • 考虑静态工厂方法代替构造器
    1. 含义更明确

类方法 & 实例方法

1
2
3
4
5
6
7
8
9
类方法:(静态方法) static修饰、可以通过类名直接访问、
实例方法: 无static修饰、必须通过创建的实例才能访问

类变量和实例变量同理

实例方法可以直接访问实例变量 ?
因为在实例方法中、有一个隐含的参数(当前操作的对象本身)
1. 类方法只能调用类方法、访问类变量, 不能访问实例方法和实例变量
2. 实例方法可以访问类方法、类变量、实例方法、实例变量

可以将类看成自定义数据类型

Note

1
2
3
4
5
6
7
8
9
10
11
12
13
1. 定义一个类本身、什么都不会做、不会分配内存、也不会执行代码
2. 声明变量本身只分配存放位置的内存空间、这块空间还未指向任何实际内容
3. p = new Point();
1) 分配内存、以存储新对象的数据(这个对象的属性、包括实例变量x|y)
2) 给实例变量设置默认值、int->0 boolean->false char->\u000 refer->null

4. 修改变量默认值
1) 定义的同时、初始化 private int x = 1;
2) 初始化代码块 private int y; {y=2}
3) 构造方法
调用顺序 1) -> 2) -> 3) 所以、若多种方式定义了默认值、前边的会被后边的覆盖

5. final修饰类变量、实例变量、表示变量只能被赋值一次、final也可以修饰实例方法

类和对象的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 程序运行时、第一次通过new创建一个类的对象的时候、or 直接通过类名访问类变量/类方法的时候、
Java会讲类加载进内场、为这个类分配一块空间、保护类的定义、有哪些变量和方法、
还有类的静态变量、并对静态变量赋初值

类加载进内存后一般不会释放、直到程序结束、一般情况下、只加载一次(静态变量在内存中只存在一份)

2. 对象 每次new、都会产生一个新的实例、会有一份独立的实例变量
每个对象除了保存实例变量的值、还保存着对应类的地址、即: 通过对象可以知道类、就能访问到类的变量和方法
实例方法可以理解为多了this参数的静态方法

对象的释放是被Java的垃圾回收机制管理的
a. 保存地址的部分分配在桟上、函数调用入栈就分配、出栈就释放
b. 保存内容的部分分配在堆上、无活跃变量指向对象的时候(已加载的类的类变量和桟中所有的变量)、
就可能被释放

类继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1. java 使用extends表明继承关系、一个类只有一个父类
2. 子类不可访问父类的私有属性和方法、可以访问 protectedpublic

3. 向上转型: 子类对象赋值给父类引用变量(转换为父类类型)、

4. 多态: 变量shape可以引用任何Shape子类类型的对象、即一种类型的变量、可以引用多种实际类型对象
变量shape有两种类型、类型Shape: 称为shape的静态类型、circle/line/arrowLine 称为shape的动态类型

5. 动态绑定: shapes[i].draw() 调用的是其对应动态类型的draw方法、称为方法的动态绑定

6. 若父类只有一个带参数的构造方法、则所有子类都必须通过super调用base的带参构造

7. 若父类构造方法调用了可被重写的方法、可能会出现意想不到的结果

8. 静态绑定: 在类的内部、访问的是当前类
在类的外部、要看如何访问、静态类型是父类、则访问的是父类

9. 静态变量和方法、一般通过类名直接访问、也可以通过实例对象来访问

10. 在有多个重名函数的时候、首先按照参数类型进行匹配、然后才看变量的动态类型、进行动态绑定

11. 模板方法: 在父类定义一个实现的模板、具体实现由子类提供

12. 子类可以升级父类的可见性、不可降低

类加载

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
在Java中、类的加载时将类的相关信息加载到内存、Java是动态加载的、第一次使用时才会加载
加载一个类时、会查看其父类是否已加载、若没有、会加载其父类

类初始化代码:
1. 定义静态变量时的赋值语句
2. 静态初始化代码块

实例初始化代码:
1. 定义实例变量时的赋值语句
2. 实例初始化代码块
3. 构造方法

类加载过程:
1. 分配内存保存类的信息
2. 给类变量赋默认值
3. 加载父类
4. 设置父子关系
5. 执行类初始化代码(先执行父类 -> 子类、不过父类执行时、子类静态变量是有值的、默认值)

内存分为堆(存放动态分配的对象)和桟(存放函数的局部变量)、还有一个内存区: 方法区(存放类的信息)

创建对象:
1. 分配内存
包括本类和父类的所有实例变量、但不包括任何静态变量
实例化代码从父类开始、再执行子类
但: 在任何类执行初始化代码之前、所有的实例变量都已设置完默认值

2. 对所有的实例变量赋默认值
3. 执行实例初始化代码

**Note**
每个对象除了保存类的实例变量之外、还保存着实际类信息的引用

虚方法表

1
2
在类加载的时候、为每个类创建一个表、包括类的对象所有动态绑定的方法及地址、包括父类的方法
但同一个方法只有一条记录、子类重写之后就只会保留子类的

疑问:

1
2
3
4
5
6
7
8
Q. 实例变量的初始化是在new的时候进行的、类变量的初始化呢 ?(MyNumber.class)
A. Java对静态类的初始化
1) 为类里边的静态变量分配内存空间、并赋初值
2) 按照初始化的代码顺序对类变量进行初始化

Q: 父子类、同名静态变量在内存中如何保存 ?
同名实例变量呢 ?
A: 对于子类来说、会保存两份、静态类型是哪个的时候、访问的就是哪个

参考:
https://mp.weixin.qq.com/s/u_WmkE5meMWuZ81G5gHhBQ

代码整理:
https://github.com/niujing1/javaLearn/tree/master

线程池类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. newSingleThreadExecutor 
-> return new ThreadPoolExecutor(1, 1, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
只使用一个线程、使用无界队列 LinkedBlockingQueue, 线程创建后不会超时终止、该线程顺序执行所有任务
适用于需要确保所有任务呗顺序执行的场合

1. newFixedThreadPool
-> ThreadPoolExecutor(nThreads, nThreads, 0L,
TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())
保持固定线程数、新的任务进入、会放进任务队列

2. newCachedThreadPool
-> ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L,
TimeUnit.SECONDS, new SynchronousQueue<Runnable>())
任务到达、有空闲线程就复用、无空闲线程就创建
任务执行完、线程最大空闲时间60s、超过60s会被销毁

3. new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 3,
200, 1,TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(100000), new DefaultThreadFactory())

核心参数

1
2
3
4
corePoolSize: 线程池中维护的核心线程数、空闲依然存在、除非设置了 allowCoreThreadTimeOut 参数
maximumPoolSize: 最大线程数
keepAliveTime: 线程池中的线程数 > 核心线程数的时候、空闲线程最大idle的时间
workQueue: 任务队列

Queue类型

1
2
3
4
1. LinkedBlockingQueue
2. SynchronousQueue
3. ArrayBlockingQueue
4.

reject

1
2
3
4
5
6
7
8
9
1. ThreadPoolExecutor.AbortPolicy:这就是默认的方式,抛出异常
2. ThreadPoolExecutor.DiscardPolicy:静默处理,忽略新任务,不抛异常,也不执行
3. ThreadPoolExecutor.DiscardOldestPolicy:将等待时间最长的任务扔掉,然后自己排队
4. ThreadPoolExecutor.CallerRunsPolicy:在任务提交者线程中执行任务,而不是交给线程池中的线程执行

拒绝策略只有在队列有界,且maximumPoolSize有限的情况下才会触发
如果队列无界,服务不了的任务总是会排队,但这不见得是期望的,因为请求处理队列可能会消耗非常大的内存,甚至引发内存不够的异常
如果队列有界但maximumPoolSize无限,可能会创建过多的线程,占满CPU和内存,使得任何任务都难以完成
在任务量非常大的场景中,让拒绝策略有机会执行是保证系统稳定运行很重要的方面

线程池的选择

1
2
3
4
5
6
7
8
1. 在系统负载很高的情况下、newFixedThreadPool可以通过队列对新任务排队、保证有足够的资源处理实际任务
newCachedThreadPool会为每一个任务创建一个线程、导致创建过多的线程竞争CPU和内存资源、
使得任何任务都难以完成、此时使用newFixedThreadPool更合适
2. 若系统负载不太高、单个任务执行时间也比较短、newCachedThreadPool 因为不用排队、效率可能更高

3. 系统负载可能极高的情况下、两者都不是最好的选择
newFiexedThreadPool的问题是: 队列过长、占用更多内存
newCachedThreadPool的问题是: 线程数过多、导致过多线程竞争CPU和内存资源

线程池的死锁

1
2
3
4
5
6
7
8
9
10
若任务之间有依赖、可能会出现线程池的死锁
eg. 线程池的大小为5、taskA 提交了5个任务、taskA会提交5个taskB、taskB因为无法创建新的线程只能在等待队列进行等待
而taskA一直在等待taskB的处理结果、这样就会造成线程池的死锁

resolve:
1. 使用 newCachedThreadPool 替代 fixed: 这样、有新的任务提交就会创建新的线程
2. 使用 SynchronousQueue 这样、入队成功就意味着有线程接受处理、若入队失败、就会触发reject机制、不管怎么样、都不会死锁了
static ExecutorService executor = new ThreadPoolExecutor(
THREAD_NUM, THREAD_NUM, 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());

note

1
2
3
4
5
6
1. 核心线程不会预先创建,只有当有任务时才会创建
2. 核心线程不会因为空闲而被终止,keepAliveTime参数不适用于它
3. 核心线程干预
1) public int prestartAllCoreThreads() 预先创建所有的核心线程
2) public boolean prestartCoreThread() 创建一个核心线程,如果所有核心线程都已创建,返回false
3) public void allowCoreThreadTimeOut(boolean value) 如果参数为true,则keepAliveTime参数也适用于核心线程

hbase

install

1
2
3
4
1. brew install hbase
2. http://hbase.apache.org/book.html#quickstart
tar xzvf hbase-3.0.0-SNAPSHOT-bin.tar.gz
cd hbase-3.0.0-SNAPSHOT/

modify config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1. conf/hbase-env.sh 添加Java jdk路径
vim xxxx/libexec/conf/hbase-env.sh

export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home"

2. conf/hbase-site.xml 添加hbase文件存储路径

<configuration>
<property>
<name>hbase.rootdir</name>
<value>file:///usr/local/var/hbase</value>
</property>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/usr/local/var/zookeeper</value>
</property>
</configuration>

start server

1
/usr/local/Cellar/hbase/{version}/libexec/bin/start-hbase.sh

start shell

1
hbase shell

command

base command

1
2
3
4
5
status 查询服务器的状态
version 查询hbase版本
whoami 查看连接用户

list 查询库中所有表

DDL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. create
create 'table_name', 'cf1', 'cf2'

2. drop
disable 'table_name' 删除之前需要先让表失效、修改表结构是也是
drop 'table_name' 删除

3. exists
exists 'table_name' 查看表是否存在

4. describe 查看表结构
describe 'table_name'

5. enable 使表有效
enable 'table_name'

6. modify table structure
1) alter 'table_name' 'cf3' # 新增列族
2) alter 'test', {NAME=>'cf3', METHOD=>'delete'} # 删除列族

DML

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
1. add
put 'table_name', 'rowkey', '列族名 1: 列名 1', 'value' #同一个rowkey、执行两次put、认为是更新操作
eg. put 'test','row_key1','cf1:a','a'

2. incr

3. count 查询表的行数(比较耗时)
count 'table_name'

4. select
1) get 'table_name', 'rowkey', '列族名:列名' #查询指定列族的指定列的值
eg. get 'test', 'row_key1', 'cf1:a,cf4'

2) get 'table_name', 'rowkey' #获取指定row_key的所有数据
eg. get 'test', 'row_key1'

3) get 'table_name', 'rowkey', {COLUMN=>'列族名:列', TIMESTAMP=>1373737746997} # 获取指定时间戳的数据
get 'test', 'row_key1', {COLUMN=>'cf1:a',TIMESTAMP=>1559367213477}

4) get 'table_name', 'rowkey', {COLUMN => '列族名:列名', VERSIONS => 2} 获取多个版本值、默认返回第一个
get 'test', 'row_key1', {COLUMN=>'cf1:a',VERSIONS=>2}

5. delete

1) delete 'table_name', 'rowkey', '列族名:列名' 删除指定rowkey的指定列族的列名数据
eg. delete 'test','row_key1','cf1:a'

2) delete 'table_name', 'rowkey', '列族名' 删除指定rowkey指定列族的数据
eg. delete 'test','row_key1','cf1'

3) deleteall 'table_name', ’rowkey' 删除rowkey所有column的calue、删除整行数据

6. scan 'table_name' 全表扫描
scan 'test'

7. truncate 'table_name' 删除全表数据

8. hbase shell test.hbaseshell 执行shell脚本

说明

1
2
3
4
5
6
7
1. 行以 rowkey 作为唯一标识、最大长度 64KB
不支持order by只能按照rowkey或者range或者全表扫描

2. 列族是列的集合 列族:列

3. HBase 通过 rowcolumn 确定一份数据
tableName + RowKey + ColumnKey + Timestamp => value 唯一确定。Cell 中数据没有类型,字节码存储

reference

http://einverne.github.io/post/2017/02/hbase-introduction-and-use.html

http://einverne.github.io/post/2017/02/hbase-shell-command.html

bean的作用域

1
2
3
4
5
6
Spring的`scope` :
`Singleton` 一个spring容器中、只有一个`bean` 的实例、spring默认配置
`Prototype` 每次调用新建一个bean
`Request` web项目中、给每个http request请求一个bean实例
`Session` web项目中、给每个http session一个bean实例
`GlobalSession` 只有在Portal应用中有、给每个global http request一个bean实例

postConstructor

1
2
3
4
5
6
7
8
9
10
@PostConstruct 在 construct之后执行、
相当于java配置方式的 @Bean(initMethod='xxx')、
相当于xml配置方式的 init-method

@PreDestroy 在bean销毁之前执行、
相当于java配置方式的 @Bean(deatroyMethod='xxx')
相当于xml配置方式的 destroy-method
```

#### profile

提供不同环境不同配置文件的支持

1
2

#### 事件

Spring的事件为Bean与Bean之间的通信提供了支持、

1) 自定义事件 继承ApplicationEvent
2) 定义事件监听器 实现 ApplicationListener
3) 使用容器发布事件

1
2

#### 任务
  1. 异步任务 @Async
  2. 规划任务 @Scheduled 每隔固定时间执行
1
2

#### 桟

主要用来存放函数调用所需要的数据(函数参数、返回地址及函数内部的局部变量)、但、返回值不在桟中、会有一个专门的返回值存储器、

1
2

#### 变量的生命周期
  1. 函数中的参数和函数内定义的变量、都分配在桟上、在函数调用时被分配、调用结束释放
  2. 数组和对象 存放变量地址的空间是分配在桟上的、存放变量内容的空间是分配在堆上的
    函数调用结束、存放变量地址的空间会被立即释放、而存放内容的空间不会、它会因为没有变量引用、而被垃圾回收机制回收掉
    1
    2

    #### 类和对象的声明周期
    类加载进内存后、一般不会释放、直到程序结束、一般情况下、类只会加载1次、所以、静态变量在内存中只有一份

对象:每次new创建一个对象的时候、对象产生、在内存中、会存储这个对象的实例变量值、每new一次、对象就会产生一个、就会有一份独立的实例变量

@Scheduled 注解、简单轻量级task配置

@Scheduled 使用:

  • @Scheduled(cron = "0 5 * * * * ?") 10分钟执行1次
  • @Scheduled(fixedRate = 2000) 每2s执行1次、不用等待上次执行完成
  • @Scheduled(fixedDelay = 2000) 等待上次请求结束后、delay 2s 执行下次任务
  • @Scheduled(fixedDelay = 2000, initDelay = 2000) 项目启动成功后、延迟2s执行任务

@Controller mvc中、声明一个控制器
@Component 声明一个通用组件
@Repository 声明一个dao组件
@Service 声明一个service组件

@Bean 声明一个bean容器
@Configuration 声明配置类
@ComponentScan 包扫描

@Async声明一个异步方法
@EnableAsync 开启异步任务支持
@Scheduled 声明一个计划任务
fixdRate 表明每隔固定时间间隔执行
cron表明按照cron表达式在指定时间执行
@EnableScheduling 开启计划任务支持
@EnableCaching 开启注解式的缓存支持

@RequestMapping 配置url和方法之间的映射关系
@Conditional 条件注解
@ResponseBody 将返回值放在response返回体内、而不是返回一个页面
@RequestBody允许将request参数放在request体中、而不是放在连接地址后边
@PathVariable用来接收路径参数

组合注解
@WiselyConfiguration 代替 @Configuration + @ComponentScan
@RestController 代替 @Controller + @ResponseBody
@SpringBootApplication 组合了
@Configuration+@EnableAutoConfiguration+@ComponentScan

@ConditionalOnBean当容器里有指定的bean的条件下
@ConditionalOnClass 当类路径下有指定的类的条件下
@ConditionalOnExpression基于SpEL做判断
@ConditionalOnJava 基于jvm版本做判断
@ConditionalOnMissingBean 当容器中无指定bean的条件下
@ConditionalOnMissingClass 类路径下无指定class的情况下
@ConditionalOnNotWebApplication 当前项目不是web项目的情况下
@ConditionalOnWebApplication 当前项目是web项目的情况下
@ConditionalOnProperty 指定的属性是否有指定值
@ConditionalOnResource 类路径是否有指定值

参考配置项

tickTime 用于计算的时间单元、eg. session超时、N*tickTime
initLimit 用于集群、允许从节点连接、并同步到master节点的初始化连接时间、以tickTime的倍数来表示
syncLimit 用于集群、master主节点与从节点之间发送消息、请求和应答的时间长度(心跳机制)
dataDir 数据文件目录、必须
dataLogDir 日志目录、非必须、默认dataDir
clientPort 连接服务器的端口、默认 2181

client 连接

zkCli.sh 默认连接2181

client 命令

ls 与linux下ls同义
ls 等同于 ls + stat
stat 状态显示 zZxid zookeeper为数据分配的id pZxid 子节点的id
get 查看节点数据
create 创建节点 -e 临时节点
set 修改节点数据
delete 删除节点数据

ACL

构成: scheme: 采用的权限机制
(word:anyone:[permissions] |
auth:user:password:[permissions] |
digest:user:BASE64(SHA1(pass)):[permissions])
(ip:192.168.1.1:[permission])
(super: 代表超管、拥有所有的权限)

id: 代表允许访问的机制

permissons: 权限

权限字符缩写 crdwa
create: 创建子节点
read: 获取节点、子节点
write: 设置节点数据
delete: 删除子节点
admin: 设置权限

getAcl 获取节点的acl权限信息
setAcl 设置某个节点的acl权限信息
addAuth 输入认证权限信息、注册时、输入明文密码(登录)、但在zk的系统里、是以密文存在的

four letter cmd

stat 当前节点的状态信息
ruok 当前节点是否ok
conf 查看服务器相关的配置
cons 展示连接到server的client信息
envi 打印环境变量信息
mntr 监控zk的健康信息
wchs watcher的信息
wchc session与watch对应关系信息
wchp path与watch对应关系