Browse Source

first commit

root 5 years ago
commit
e2e51e007b

+ 15 - 0
_posts/Java-JodaTime.md

@@ -0,0 +1,15 @@
+---
+title: JodaTime常用方法
+date: 2020-06-13
+tags: Java
+---
+## Joda Time
+
+### 取整天的方法
+``` java
+DateTime now = new DateTime(); // 2016-02-26T16:51:28.749+08:00
+now.dayOfWeek().roundCeilingCopy(); // 2016-02-27T00:00:00.000+08:00
+now.dayOfWeek().roundFloorCopy(); // 2016-02-26T00:00:00.000+08:00
+now.minuteOfDay().roundFloorCopy(); // 2016-02-26T16:51:00.000+08:00
+now.secondOfMinute().roundFloorCopy(); // 2016-02-26T16:51:28.000+08:00
+```

+ 76 - 0
_posts/Linux-nohup.md

@@ -0,0 +1,76 @@
+---
+title: Linux 技巧:让进程在后台可靠运行的几种方法
+date: 2016-11-08
+tags: Linux
+comments: false
+---
+我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开连接的干扰呢?下面举了一些例子, 您可以针对不同的场景选择不同的方式来处理这个问题。
+
+## nohup/setsid/&
+
+如果只是临时有一个命令需要长时间运行,什么方法能最简便的保证它在后台稳定运行呢?
+
+我们知道,当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。因此,我们的解决办法就有两种途径:要么让进程忽略 HUP 信号,要么让进程运行在新的会话里从而成为不属于此终端的子进程。
+
+**1. nohup**
+
+nohup 无疑是我们首先想到的办法。顾名思义,nohup 的用途就是让提交的命令忽略 hangup 信号。让我们先来看一下 nohup 的帮助信息:
+
+可见,nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即可,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般我们可在结尾加上 **"&"**来将命令同时放入后台运行,也可用 `">filename 2>&1"`来更改缺省的重定向文件名。
+
+**2。setsid**
+
+nohup 无疑能通过忽略 HUP 信号来使我们的进程避免中途被中断,但如果我们换个角度思考,如果我们的进程不属于接受 HUP 信号的终端的子进程,那么自然也就不会受到 HUP 信号的影响了。setsid 就能帮助我们做到这一点。让我们先来看一下 setsid 的帮助信息:
+
+可见 setsid 的使用也是非常方便的,也只需在要处理的命令前加上 setsid 即可。
+
+值得注意的是,上例中我们的进程 ID(PID)为31094,而它的父 ID(PPID)为1(即为 init 进程 ID),并不是当前终端的进程 ID。请将此例与nohup 例(#nohup)中的父 ID 做比较。
+
+**3。&**
+
+这里还有一个关于 subshell 的小技巧。我们知道,将一个或多个命名包含在"()"中就能让这些命令在子 shell 中运行中,从而扩展出很多有趣的功能,我们现在要讨论的就是其中之一。
+
+当我们将"&"也放入"()"内之后,我们就会发现所提交的作业并不在作业列表中,也就是说,是无法通过 `jobs`来查看的。让我们来看看为什么这样就能躲过 HUP 信号的影响吧。
+
+从上例中可以看出,新提交的进程的父 ID(PPID)为1(init 进程的 PID),并不是当前终端的进程 ID。因此并不属于当前终端的子进程,从而也就不会受到当前终端的 HUP 信号的影响了。
+
+## disown
+
+我们已经知道,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响。但是如果我们未加任何处理就已经提交了命令,该如何补救才能让它避免 HUP 信号的影响呢?
+
+这时想加 nohup 或者 setsid 已经为时已晚,只能通过作业调度和 disown 来解决这个问题了。让我们来看一下 disown 的帮助信息:
+
+可以看出,我们可以用如下方式来达成我们的目的。
+
+* 用 `disown -h jobspec`来使 **某个作业**忽略HUP信号。
+* 用 `disown -ah `来使 **所有的作业**都忽略HUP信号。
+* 用 `disown -rh `来使 **正在运行的作业**忽略HUP信号。
+
+需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用 `jobs`来查看它,但是依然能够用 `ps -ef`查找到它。
+
+但是还有一个问题,这种方法的操作对象是作业,如果我们在运行命令时在结尾加了 **"&"**来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过 `jobs`命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!
+
+CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用 `jobs`命令来查询它的作业号,再用 `bg jobspec`来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,请慎用此方法。
+
+## screen
+
+我们已经知道了如何让进程免受 HUP 信号的影响,但是如果有大量这种命令需要在稳定的后台里运行,如何避免对每条命令都做这样的操作呢?
+
+此时最方便的方法就是 screen 了。简单的说,screen 提供了 ANSI/VT100 的终端模拟器,使它能够在一个真实终端下运行多个全屏的伪终端。screen 的参数很多,具有很强大的功能,我们在此仅介绍其常用功能以及简要分析一下为什么使用 screen 能够避免 HUP 信号的影响。我们先看一下 screen 的帮助信息:
+
+使用 screen 很方便,有以下几个常用选项:
+
+* 用 `screen -dmS session name`来建立一个处于断开模式下的会话(并指定其会话名)。
+* 用 `screen -list `来列出所有会话。
+* 用 `screen -r session name`来重新连接指定会话。
+* 用快捷键 `CTRL-a d `来暂时断开当前会话。
+
+当我们用"-r"连接到 screen 会话后,我们就可以在这个伪终端里面为所欲为,再也不用担心 HUP 信号会对我们的进程造成影响,也不用给每个命令前都加上"nohup"或者"setsid"了。这是为什么呢?让我来看一下下面两个例子吧。
+
+我们可以看出,未使用 screen 时我们所处的 bash 是 sshd 的子进程,当 ssh 断开连接时,HUP 信号自然会影响到它下面的所有子进程(包括我们新建立的 ping 进程)。
+
+而使用了 screen 后就不同了,此时 bash 是 screen 的子进程,而 screen 是 init(PID为1)的子进程。那么当 ssh 断开连接时,HUP 信号自然不会影响到 screen 下面的子进程了。
+
+现在几种方法已经介绍完毕,我们可以根据不同的场景来选择不同的方案。nohup/setsid 无疑是临时需要时最方便的方法,disown 能帮助我们来事后补救当前已经在运行了的作业,而 screen 则是在大批量操作时不二的选择了。
+
+

+ 26 - 0
_posts/Linux.md

@@ -0,0 +1,26 @@
+---
+title: linux 常用命令
+date: 2020-06-14
+tags: Linux
+---
+### 编译
+Mac 下编译 Linux 和 Windows 64位可执行程序
+``` bash
+$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
+$ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
+```
+Linux 下编译 Mac 和 Windows 64位可执行程序
+``` bash
+$ CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
+$ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
+```
+
+### 运行
+
+``` bash
+$ nohup go run aaronwei.go > /opt/logs/log/bufOverflow.log 2>&1 &
+$ nohup go run main.go > /opt/logs/log/rebot.log 2>&1 &
+$ nohup go run setting.go > /opt/logs/setting.log 2>&1 &
+$ nohup ./gogs web > /home/gogs/log/gogs.log 2>&1 &
+$ nohup hexo s > /opt/logs/blog.log 2>&1 &
+```

+ 11 - 0
_posts/Mysql.md

@@ -0,0 +1,11 @@
+---
+title: MYSQL
+date: 2020-06-15
+tags: Mysql
+---
+<div align=center><h2>MYSQL相关</h2></div>
+
+### 查看是否有未提交的日志
+``` sql
+    select * from information_schema.innodb_trx ;
+```

+ 12 - 0
_posts/first_blog.md

@@ -0,0 +1,12 @@
+---
+title: 第一个博客
+date: 2019-09-09
+comments: false
+---
+# 欢迎来到我博客
+
+
+
+
+
+

+ 466 - 0
_posts/go-2.md

@@ -0,0 +1,466 @@
+---
+title: Golang高阶:Golang1.5到Golang1.12包管理
+date: 2020-06-29 12:09:08
+---
+`Golang` 是一门到如今有十年的静态高级语言了,2009年的时候算是正式推出了,然后到最近的一两年,2017-2018年的时候,突然直线上升,爆火了,得益于容器化运维/直播/短视频/区块链...
+
+`Golang` 语法简单,简单即是复杂,软件构建的核心在于将复杂的东西简单化,处理好复杂度。
+
+作为一个 `gopher`,我们要知道他的包管理,这样才能合理化代码结构,做好工程管理。( `gopher`:地鼠)
+
+`Golang` 的包管理一直让人口病,一开始它用 `GOPATH` 来进行依赖库管理,特别简单粗暴。
+
+如果环境变量:
+
+```
+export GOROOT=/home/love/go
+export GOPATH=/home/love/code
+export GOBIN=$GOROOT/bin
+```
+
+上面 `GOROOT` 是指 `Golang&#x7F16;&#x8BD1;&#x5668;&#x4EE5;&#x53CA;&#x5176;&#x5DE5;&#x5177;&#x94FE;&#xFF0C;&#x57FA;&#x7840;&#x6E90;&#x7801;&#x5E93;`所在的目录, `GOPATH` 是用户自定义的代码所在位置。
+
+以下 `GOPATH` 的结构如下:
+
+```
+├── src
+    └── github.com
+        └── hunterhug
+            └── rabbit
+                └── a
+                    └── a.go
+                └── main.go
+├── bin
+├── pkg 
+```
+
+我们写的开发包有简单易懂的路径之分,比如我的包叫 `github/hunterhug/rabbit`,那么结构如上面一样。
+
+我们进入到 `rabbit` 目录, `main.go` 代码:
+
+```
+package main
+import "github/hunterhug/rabbit/a"
+
+func main(){
+  ...
+
+}
+```
+
+然后 `go build` 的话,找包时,就会从 `GOPATH src` 下面开始找,比如 `rabbit` 包下的 `main.go` 依赖了 `github/hunterhug/rabbit/a`,那么它首先从 `src` 下面按路径往下拼接查找,然后就找到了,最后生成和包名 `github/hunterhug/rabbit` 一样的一个叫 `rabit` 的二进制。
+
+如果我们 `go install`的话,这个二进制就会保存在 `GOBIN` 下(如果不存在 `GOBIN`,会保存在 `GOPATH bin` 下)。如果我们要编译时,缺少包,那么 `go get -v` 将会下载依赖包源码到 `GOPATH src` 下,然后在 `GOPATH pkg` 目录下生成该包的静态库(下次用就不用再从源码编译了,算缓存)。
+
+但是我们包找不到时:
+
+```
+love@love:~/code/src/github.com/hunterhug/fafacms$ go build
+core/server/server.go:4:2: cannot find package "github.com/gin-contrib/cors" in any of:
+        /home/love/go/src/github.com/gin-contrib/cors (from $GOROOT)
+        /home/love/code/src/github.com/gin-contrib/cors (from $GOPATH)
+```
+
+我们发现,原来,其实是先去 `GOROOT` 下找包,找不到包,再去 `GOPATH` 找,流下了感动的泪水!比如我们的 `GOPATH` 下建了一个 `fmt` 包:
+
+```
+package fmt
+
+func PPrintln() {
+    print("i am diy fmt")
+}
+
+```
+
+但是我们想引用这个库, `main.go` 使用:
+
+```
+package main
+import fmt
+func main(){
+  fmt.PPrintln()
+}
+```
+
+发现引用不了,2333! 所以, `GOPATH` 下的包最好不要和 `GOROOT` 下的标准库重名!
+
+你再看下 `GOROOT` 的结构:
+
+```
+├── src
+    └── time
+    └── fmt
+├── bin
+├── pkg 
+```
+
+这不和我们的 `GOPATH` 很像吗,对,现在的 `Golang&#x7F16;&#x8BD1;&#x5668;` 是自编译的,就是用 `Golang` 来写 `Golang&#x7F16;&#x8BD1;&#x5668;`,它的编译器及中间产物,基础库等,保持和 `GOPATH` 一毛一样,无缝衔接。
+
+但是不同依赖包是有版本的,版本变了怎么办?这就需要人工管理了。
+
+自己管理库版本,想想都不太可能,毕竟 `Java` 有 `maven`, `Python` 有 `pip`, `PHP` 有 `compose`, `NodeJs` 有 `npm`。
+
+于是从 `Golang1.5` 开始推出 `vendor` 文件夹机制( `vendor`:供应商/小贩)。
+
+从 `Golang1.6` 正式开启这个功能。
+
+比如我们的包叫 `awesomeProject`,在 `GOPATH` 下结构:
+
+```
+├── src
+    └── awesomeProject
+        └── vendor
+            └── fmt
+                └── fmt.go
+        └── main.go
+├── pkg 
+```
+
+其中 `main.go`:
+
+```
+package main
+
+import "fmt"
+
+func main() {
+    fmt.PPrintln()
+}
+```
+
+我们进入 `awesomeProject` 目录,并且 `go build`, 偶也成功。
+
+这下子不会像上面没 `vendor` 时直接引用 `GOROOT` 的标准包了,我们终于可以用和标准包重名的包了,那就是放在和 `main.go` 同目录的 `vendor` 下面!
+
+这下子,我们 `import` 的包会先在同级 `vendor` 下找,找不到再按照以前的方式。
+
+如果我们将 `main` 改成引用一个不存在的包 `b`:
+
+```
+package main
+
+import (
+    "b"
+)
+
+func main() {
+    b.P()
+}
+```
+
+然后 `go build` 提示:
+
+```
+main.go:4:2: cannot find package "b" in any of:
+        /home/love/code/src/awesomeProject/vendor/b (vendor tree)
+        /home/love/go/src/b (from $GOROOT)
+        /home/love/code/src/b (from $GOPATH)
+```
+
+如果此时我们再任性一点,在 `GOPATH src` 下建立一个空的 `vendor` 文件夹,则会提示:
+
+```
+main.go:4:2: cannot find package "b" in any of:
+        /home/love/code/src/awesomeProject/vendor/b (vendor tree)
+        /home/love/code/src/vendor/b
+        /home/love/go/src/b (from $GOROOT)
+        /home/love/code/src/b (from $GOPATH)
+```
+
+好了,我们发现现在的加载方式是:
+
+```
+包同目录下的vendor
+GOPATH src 下的vendor
+GOROOT src
+GOPATH src
+```
+
+如果在 `GOROOT` 和 `GOPATH` 下建 `vendor` 会怎么样?我们就不止疼了,233。。
+
+好了,现在问题就是 `vendor` 是怎么冒泡的,如果我 `main.go` 引用了 `vendor/b`,而 `b` 包里面引用了一个 `c` 包。此时 `vendor/b` 会怎么找库?
+
+```
+├── src
+    └── awesomeProject
+        └── vendor
+            └── b
+                └── b.go
+        └── main.go
+├── pkg 
+```
+
+现在 `vendor/b/b.go` 的内容:
+
+```
+package b
+
+import "c"
+
+func P() {
+    print(" i am vendor b\n")
+    c.P()
+}
+```
+
+我们进入 `awesomeProject` 项目 `go build`,出现:
+
+```
+vendor/b/b.go:3:8: cannot find package "c" in any of:
+    /home/love/code/src/awesomeProject/vendor/c (vendor tree)
+    /home/love/code/src/vendor/c
+    /home/love/go/src/c (from $GOROOT)
+    /home/love/code/src/c (from $GOPATH)
+```
+
+现在加载流程是:
+
+```
+包同目录的包(即b包同目录看看有没有c包)
+GOPATH src 下的vendor
+GOROOT src
+GOPATH src
+```
+
+此时我们在 `vendor/b` 下建一个空 `vendor`:
+
+```
+├── src
+    └── awesomeProject
+        └── vendor
+            └── b
+                └── vendor
+                └── b.go
+        └── main.go
+├── pkg 
+```
+
+进入 `awesomeProject` 项目再 `go build` 会出现:
+
+```
+vendor/b/b.go:3:8: cannot find package "c" in any of:
+    /home/love/code/src/awesomeProject/vendor/b/vendor/c (vendor tree)
+    /home/love/code/src/awesomeProject/vendor/c
+    /home/love/code/src/vendor/c
+    /home/love/go/src/c (from $GOROOT)
+    /home/love/code/src/c (from $GOPATH)
+```
+
+如果我们再满足上面的 `c` 包,同理在 `c` 包建一个空 `vendor` :
+
+```
+├── src
+    └── awesomeProject
+        └── vendor
+            └── b
+                └── vendor
+                    └── c
+                        └── vendor
+                        └── c.go
+                └── b.go
+        └── main.go
+├── pkg 
+```
+
+但 `c` 包 `c.go` 引用了不存在的 `d` 包:
+
+```
+package c
+
+import "d"
+
+func P() {
+    d.P()
+}
+
+```
+
+进入 `awesomeProject` 项目再 `go build` 会出现:
+
+```
+vendor/b/vendor/c/c.go:3:8: cannot find package "d" in any of:
+    /home/love/code/src/awesomeProject/vendor/b/vendor/c/vendor/d (vendor tree)
+    /home/love/code/src/awesomeProject/vendor/b/vendor/d
+    /home/love/code/src/awesomeProject/vendor/d
+    /home/love/code/src/vendor/d
+    /home/love/go/src/d (from $GOROOT)
+    /home/love/code/src/d (from $GOPATH)
+```
+
+发现, 查找包 `vendor` 是往上冒泡的, 一个包引用另一个包,先看看 同目录 `vendor` 下有没有这个包, 没有的话一直追溯到上一层 `vendor` 看有没有,没有的话再上一层<br> `vendor`,直到 `GOPATH src/vendor`。
+
+所以现在的加载流程是:
+
+```
+包同目录下的vendor
+包目录向上的最近的一个vendor
+...
+GOPATH src 下的vendor
+GOROOT src
+GOPATH src
+```
+
+总结: `vendor` 向上冒泡!!!!
+
+这样的话, 我们可以把包的依赖都放在 `vendor` 下,然后提交到仓库,这样可以省却拉取包的时间,并且相对自由,你想怎么改都可以,你可以放一个已经被人删掉的 `github` 包在 `vendor` 下。这样,依然手动,没法管理依赖版本。
+
+所以很多第三方,比如 `glide` , `godep`, `govendor` 工具出现了, 使用这些工具, 依赖包必须有完整的 `git` 版本, 然后会将所有依赖的版本写在一个配置文件中。
+
+比如 `godep` :
+
+```
+go get -v github.com/tools/godep
+```
+
+在包下执行
+
+```
+godep save
+```
+
+会生成 `Godeps/Godep.json`记录依赖版本,并且将包收集于 当前 `vendor`下。
+
+`Golang 1.11` 开始, 实验性出现了可以不用定义 `GOPATH` 的功能,且官方有 `go mod` 支持。 `Golang 1.12` 更是将此特征正式化。
+
+现在用 `Golang1.12` 进行:
+
+```
+go mod init
+go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'
+```
+
+其中 `GO111MODULE=auto` 是一个开关,开启或关闭模块支持,它有三个可选值: `off`/ `on`/ `auto`,默认值是 `auto`。
+
+在使用模块的时候, `GOPATH` 是无意义的,不过它还是会把下载的依赖储存在 `GOPATH/src/mod` 中,也会把 `go install` 的结果放在 `GOPATH/bin`(如果 `GOBIN` 不存在的话)
+
+我们将项目移出 `GOPATH`,然后:
+
+```
+go mod init
+```
+
+出现:
+
+```
+go: cannot determine module path for source directory /home/love/awesomeProject (outside GOPATH, no import comments)
+```
+
+现在 `main.go` 改为:
+
+```
+package main // import "github.com/hunterhug/hello"
+
+import (
+    "b"
+)
+
+func main() {
+    b.P()
+}
+```
+
+将会生成 `go.mod`:
+
+```
+module github.com/hunterhug/hello
+
+go 1.12
+```
+
+此时我们:
+
+```
+go build
+build github.com/hunterhug/hello: cannot load b: cannot find module providing package b
+```
+
+这下没法查找 `vendor` 了,我们加上参数再来:
+
+```
+go build -mod=vendor
+build github.com/hunterhug/hello: cannot load c: open /home/love/awesomeProject/vendor/c: no such file or directory
+```
+
+流下了感动的泪水, `vendor` 冒泡呢?原来启用了 `go.mod`, `vendor` 下的包 `b` 无法找到 `b/vendor` 下的包 `c`,只能找到一级,2333333,这是好还是坏?
+
+一般情况下, `vendor` 下面有 `vendor` 是不科学的, `godep` 等工具会将依赖理顺,确保只有一个 `vendor`。
+
+那么 `go.mod` 导致 `vendor` 无法冒泡产生的影响,一点都不大,流下感动的泪水。
+
+现在我们来正确使用 `go mod`, 一般情况下:
+
+```
+省略N步
+```
+
+到了这里,我们很遗憾的说再见了,现在 `go mod` 刚出来, 可能还会再更新,您可以谷歌或者其他方式搜索这方面的文章,或者:
+
+```
+go help modules
+```
+
+这一部分可能隔一段时间再细写。
+
+目前生产环境用 `go mod` 还不太现实, 我还是先推荐定义 `GOPATH` 和 `vendor` 用法。
+
+装环境太难, 我的天啊, 我每次都要装环境, 我们可以用下面的方法 `So easy` 随时切换 `Golang` 版本。
+
+如果你的 `Golang` 项目依赖存于 `vendor` 下,那么我们可以使用多阶段构建并打包成容器镜像, `Dockefile` 如下:
+
+```
+FROM golang:1.12-alpine AS go-build
+
+WORKDIR /go/src/github.com/hunterhug/fafacms
+
+COPY core /go/src/github.com/hunterhug/fafacms/core
+COPY vendor /go/src/github.com/hunterhug/fafacms/vendor
+COPY main.go /go/src/github.com/hunterhug/fafacms/main.go
+
+RUN go build -ldflags "-s -w" -o fafacms main.go
+
+FROM alpine:3.9 AS prod
+
+WORKDIR /root/
+
+COPY --from=go-build /go/src/github.com/hunterhug/fafacms/fafacms /bin/fafacms
+RUN chmod 777 /bin/fafacms
+CMD /bin/fafacms $RUN_OPTS
+```
+
+其中 `github.com/hunterhug/fafacms` 是你的项目。使用 `golang:1.12-alpine` 来编译二进制,然后将二进制打入基础镜像: `alpine:3.9`,这个镜像特别小。
+
+编译:
+
+```
+sudo docker build -t hunterhug/fafacms:latest .
+```
+
+我们多了一个镜像 `hunterhug/fafacms:latest`, 而且特别小, 才几M 。
+
+运行:
+
+```
+sudo docker run -d  --net=host  --env RUN_OPTS="-config=/root/fafacms/config.json" hunterhug/fafacms
+```
+
+可是,如果我们用了 `cgo`, 那么请将 `Dockerfile` 改为:
+
+```
+FROM golang:1.12 AS go-build
+
+WORKDIR /go/src/github.com/hunterhug/fafacms
+
+COPY core /go/src/github.com/hunterhug/fafacms/core
+COPY vendor /go/src/github.com/hunterhug/fafacms/vendor
+COPY main.go /go/src/github.com/hunterhug/fafacms/main.go
+
+RUN go build -ldflags "-s -w" -o fafacms main.go
+
+FROM bitnami/minideb-extras-base:stretch-r165 AS prod
+
+WORKDIR /root/
+
+COPY --from=go-build /go/src/github.com/hunterhug/fafacms/fafacms /bin/fafacms
+RUN chmod 777 /bin/fafacms
+CMD /bin/fafacms $RUN_OPTS
+```

+ 38 - 0
_posts/hello-world.md

@@ -0,0 +1,38 @@
+---
+title: Hello World
+---
+Welcome to [Hexo](https://hexo.io/)! This is your very first post. Check [documentation](https://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](https://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues).
+
+## Quick Start
+
+### Create a new post
+
+``` bash
+$ hexo new "My New Post"
+```
+
+More info: [Writing](https://hexo.io/docs/writing.html)
+
+### Run server
+
+``` bash
+$ hexo server
+```
+
+More info: [Server](https://hexo.io/docs/server.html)
+
+### Generate static files
+
+``` bash
+$ hexo generate
+```
+
+More info: [Generating](https://hexo.io/docs/generating.html)
+
+### Deploy to remote sites
+
+``` bash
+$ hexo deploy
+```
+
+More info: [Deployment](https://hexo.io/docs/one-command-deployment.html)

+ 41 - 0
_posts/html2md.md

@@ -0,0 +1,41 @@
+---
+title: 一个工具简单实现简书、掘金、CSDN上一些优秀的文章保存成markdown文件
+date: 2020-06-29
+---
+
+
+### **安装**
+
+只需使用npm安装:
+
+> $ npm install clean-mark --global
+
+引申:如果是Mac电脑,加上sudo就可以安装
+
+> $ sudo npm install clean-mark --global
+
+### **使用**
+
+> $ clean-mark "http://some-website.com/fancy-article"
+
+文章将使用URL路径名自动命名。在上述情况下,名称为fancy-article.md。
+
+可以指定文件类型:
+
+> $ clean-mark" http://some-website.com/fancy-article " -t html
+
+可用的类型为: `html`, `TEXT`和 `Markdown`。
+
+还可以指定输出文件和路径:
+
+> $ clean-mark" http://some-website.com/fancy-article " -o / tmp / article
+
+在这种情况下,输出将为/tmp/article.md。该扩展名是自动添加的。
+
+### **示例**
+
+> $ clean-mark "https://blog.csdn.net/kkk_xxx/article/details/104431609" -o /Users/aaa/Desktop/js.md
+
+此示例得到的网页就是在/Users/aaa/Desktop/目录下的js.md文件
+
+更多特质可参见:[https://github.com/croqaz/clean-mark#why-](https://github.com/croqaz/clean-mark#why-)

+ 18 - 0
_posts/idea.md

@@ -0,0 +1,18 @@
+---
+title: Intellij IDEA常见问题解决办法
+tags: IDEA
+date: 2020-06-18
+---
+## Intellij IDEA常见问题解决办法
+---
+### idea报如下错误:
+
+``` info
+Command line is too long. Shorten command line for ProductCenterOpenapiApplication or also for Spring Boot default configuration.
+```
+### 解决办法:
+> 在.idea 文件夹中打开workspace.xml文件找到`<component name="PropertiesComponent">`
+
+> 在标签里加一行  `<property name="dynamic.classpath" value="true" />  `
+
+

+ 212 - 0
_posts/java-god.md

@@ -0,0 +1,212 @@
+---
+title: 提示Java工程师成神之路
+date: 2018-03-23
+---
+
+## 一、基础篇
+
+堆、栈、方法区、直接内存、堆和栈区别
+
+内存可见性、重排序、顺序一致性、volatile、锁、final
+
+内存分配策略、垃圾收集器(G1)、GC算法、GC参数、对象存活的判定
+
+oop-klass、对象头
+
+即时编译器、编译优化
+
+classLoader、类加载过程、双亲委派(破坏双亲委派)、模块化(jboss modules、osgi、jigsaw)
+
+jps, jstack, jmap、jstat, jconsole, jinfo, jhat, javap, btrace、TProfiler
+
+javac 、javap 、jad 、CRF
+
+String、Integer、Long、Enum、BigDecimal、ThreadLocal、ClassLoader & URLClassLoader、ArrayList & LinkedList、 HashMap & LinkedHashMap & TreeMap & CouncurrentHashMap、HashSet & LinkedHashSet & TreeSet
+
+JDK 6和JDK 7中substring的原理及区别、
+
+replaceFirst、replaceAll、replace区别、
+
+String对"+"的重载、
+
+String.valueOf和Integer.toString的区别、
+
+字符串的不可变性
+
+Integer的缓存机制
+
+transient、instanceof、volatile、synchronized、final、static、const 原理及用法。
+
+常用集合类的使用、ArrayList和LinkedList和Vector的区别 、SynchronizedList和Vector的区别、HashMap、HashTable、ConcurrentHashMap区别、Java 8中stream相关用法、apache集合处理工具类的使用、不同版本的JDK中HashMap的实现的区别以及原因
+
+枚举的用法、枚举与单例、Enum类
+
+bio、nio和aio的区别、三种IO的用法与原理、netty
+
+反射与工厂模式、 `java.lang.reflect.*`
+
+什么是序列化与反序列化、为什么序列化、序列化底层原理、序列化与单例模式、protobuf、为什么说序列化并不安全
+
+元注解、自定义注解、Java中常用注解使用、注解与反射的结合
+
+什么是Java消息服务、JMS消息传送模型
+
+`java.lang.management.*`、 `javax.management.*`
+
+泛型与继承、类型擦除、泛型中K T V E ? object等的含义、泛型各种用法
+
+junit、mock、mockito、内存数据库(h2)
+
+`java.lang.util.regex.*`
+
+`commons.lang`, `commons.*...` `guava-libraries` `netty`
+
+异常类型、正确处理异常、自定义异常
+
+时区、时令、Java中时间API
+
+解决乱码问题、常用编码方式
+
+Java中语法糖原理、解语法糖
+
+Thread、Runnable、Callable、ReentrantLock、ReentrantReadWriteLock、Atomic*、Semaphore、CountDownLatch、、ConcurrentHashMap、Executors
+
+自己设计线程池、submit() 和 execute()
+
+死锁、死锁如何排查、Java线程调度、线程安全和内存模型的关系
+
+CAS、乐观锁与悲观锁、数据库相关锁机制、分布式锁、偏向锁、轻量级锁、重量级锁、monitor、锁优化、锁消除、锁粗化、自旋锁、可重入锁、阻塞锁、死锁
+
+happens-before、编译器指令重排和CPU指令重
+
+synchronized是如何实现的?synchronized和lock之间关系、不使用synchronized如何实现一个线程安全的单例
+
+守护线程和非守护线程的区别以及用法
+
+## 二、 进阶篇
+
+用位运算实现加、减、乘、除、取余
+
+单例、策略、工厂、适配器、责任链。
+
+三次握手与四次关闭、流量控制和拥塞控制、OSI七层模型、tcp粘包与拆包
+
+cookie被禁用,如何实现session
+
+> 实现客户端缓存功能,支持返回304 实现可并发下载一个文件 使用线程池处理客户端请求 使用nio处理客户端请求 支持简单的rewrite规则 上述功能在实现的时候需要满足"开闭原则"
+
+Spring Boot的starter原理,自己实现一个starter
+
+## 三、 高级篇
+
+lambda表达式、Stream API、
+
+Jigsaw、Jshell、Reactive Streams
+
+局部变量类型推断、G1的并行Full GC、ThreadLocal握手机制
+
+响应式编程
+
+使用单例、使用Future模式、使用线程池、选择就绪、减少上下文切换、减少锁粒度、数据压缩、结果缓存
+
+线程Dump、内存Dump、gc情况
+
+分析死锁、分析内存泄露
+
+HeapOutOfMemory、 Young OutOfMemory、MethodArea OutOfMemory、ConstantPool OutOfMemory、DirectMemory OutOfMemory、Stack OutOfMemory Stack OverFlow
+
+内存溢出、线程死锁、类加载冲突
+
+当一个Java程序响应很慢时如何查找问题、
+
+当一个Java程序频繁FullGC时如何解决问题、
+
+如何查看垃圾回收日志、
+
+当一个Java应用发生OutOfMemory时该如何解决、
+
+如何判断是否出现死锁、
+
+如何判断是否存在内存泄露
+
+如何查看执行计划,如何根据执行计划进行SQL优化
+
+事务的隔离级别、事务能不能实现锁的功能
+
+行锁、表锁、使用数据库锁实现乐观锁、
+
+redis、memcached
+
+栈、队列、链表、数组、哈希表、
+
+二叉树、字典树、平衡树、排序树、B树、B+树、R树、多路树、红黑树
+
+各种排序算法和时间复杂度 深度优先和广度优先搜索 全排列、贪心算法、KMP算法、hash算法、海量数据处理
+
+基本概念、常见用法
+
+在linux上部署solr,solrcloud,,新增、删除、查询索引
+
+在linux上部署storm,用zookeeper做协调,运行storm hello world,local和remote模式运行调试storm topology。
+
+HDFS、MapReduce
+
+XSS的防御
+
+SQL注入、XML注入、CRLF注入
+
+MD5,SHA1、DES、AES、RSA、DSA
+
+memcached为什么可以导致DDos攻击、什么是反射型DDoS
+
+## 四、架构篇
+
+数据一致性、服务治理、服务降级
+
+2PC、3PC、CAP、BASE、 可靠消息最终一致性、最大努力通知、TCC
+
+服务注册、服务发现,服务治理
+
+怎样打造一个分布式数据库、什么时候需要分布式数据库、mycat、otter、HBase
+
+mfs、fastdfs
+
+缓存一致性、缓存命中率、缓存冗余
+
+SOA、康威定律
+
+ActiveMQ
+
+CPU、内存、磁盘I/O、网络I/O等
+
+进程监控、语义监控、机器资源监控、数据波动
+
+日志、埋点
+
+tomcat负载均衡、Nginx负载均衡
+
+DNS原理、DNS的设计
+
+数据一致性
+
+## 五、 扩展篇
+
+IaaS、SaaS、PaaS、虚拟化技术、openstack、Serverlsess
+
+Solr、Lucene、Nutch、Elasticsearch
+
+Shiro
+
+哈希算法、Merkle树、公钥密码算法、共识算法、Raft协议、Paxos 算法与 Raft 算法、拜占庭问题与算法、消息认证码与数字签名
+
+挖矿、共识机制、闪电网络、侧链、热点问题、分叉
+
+数学基础、机器学习、人工神经网络、深度学习、应用场景。
+
+TensorFlow、DeepLearning4J
+
+Groovy、Python、Go、NodeJs、Swift、Rust
+
+## 六、 推荐书籍
+
+《深入理解Java虚拟机》 《Effective Java》 《深入分析Java Web技术内幕》 《大型网站技术架构》 《代码整洁之道》 《Head First设计模式》 《maven实战》 《区块链原理、设计与应用》 《Java并发编程实战》 《鸟哥的Linux私房菜》 《从Paxos到Zookeeper》 《架构即未来》

+ 301 - 0
_posts/joda-vs-javatime.md

@@ -0,0 +1,301 @@
+---
+title: 提示Java基础之如何取舍Joda与 Java8 日期库
+date: 2020-02-28T14:35:06.258Z
+---
+在 Java8 以前,时间和日期的类库很难用,而且有线程安全等诸多问题。
+
+Joda time 弥补了 Java 在这方面的不足,但是在 Java8 时,增加了 `java.time` 包,对 Java 在日期 API 方面的进行了增强,这些代码实现了 JSR-310 的标准。Joda 的官方推荐迁移到 Java8 的时间类库上来。
+
+下面来详细对比对比一下两个类库,看看 Java8 的日期 API 是否能真正替代 Joda time。
+
+## 基础概念对比
+
+Joda Date 的核心概念,这些概念在 java time 中基本也能找到对应:
+
+### instant
+
+表示一个时刻,使用从 1970-01-01 00:00:00 至今的毫秒数表示
+
+Joda time:
+
+```
+DateTime dt = new DateTime();
+Instant instant = dt.toInstant();
+```
+
+Java time:
+
+```
+Clock clock = Clock.systemDefaultZone();
+Instant instant = clock.instant();
+```
+
+### interval 
+
+表示两个 instant 之间的间隔,左闭右开。
+
+Joda time:
+
+```
+DateTime dt = new DateTime();
+DateTime dt1 = new DateTime();
+Interval interval = new Interval(dt.toInstant(), dt1.toInstant());
+```
+
+java time 中没有提供类似的 API,因为 JSR-310 标准中没有这个概念。
+
+### duration
+
+用毫秒表示的时间段,通常从 interval 获得 Joda time:
+
+```
+DateTime dt = new DateTime();
+DateTime dt1 = new DateTime();
+Interval interval = new Interval(dt.toInstant(), dt1.toInstant());
+Duration duration = interval.toInstant();
+```
+
+Java time:
+
+```
+LocalDateTime l1 = LocalDateTime.now();
+LocalDateTime l2 = LocalDateTime.now();
+Period period = Period.between(l1.toLocalDate(), l2.toLocalDate());
+
+```
+
+### period
+
+同样表示时间段,比如 3年,5个月,而 duration 使用毫秒表示
+
+Joda time:
+
+```
+DateTime dt1 = new DateTime();
+DateTime dt2 = new DateTime();
+Period period = Period.fieldDifference(dt1.toLocalDateTime(), dt2.toLocalDateTime());
+```
+
+Java time:
+
+```
+LocalDateTime l1 = LocalDateTime.now();
+LocalDateTime l2 = LocalDateTime.now();
+Period period = Period.between(l1.toLocalDate(), l2.toLocalDate());
+```
+
+年表,这是 joda-time 设计的基础
+
+Joda time:
+
+```
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+Chronology chronology = dt.getChronology();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Java time:
+
+```
+LocalDateTime localDateTime = LocalDateTime.now();
+Chronology ch = localDateTime.getChronology();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+表示时区。
+
+Joda time:
+
+```
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+DateTimeZone dateTimeZone = dt.getZone();
+Set<string> zones = DateTimeZone.getAvailableIDs();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span></string>
+```
+
+Java time:
+
+```
+Clock clock = Clock.systemDefaultZone();
+ZoneId zoneId = clock.getZone();
+Set<string> zones = ZoneId.getAvailableZoneIds();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span></string>
+```
+
+从上面可以看到,除了 JSR-310 中没有的 Interval 的定义之外,这两个库在基础概念方面的实现相差不大。
+
+> 因为 Unix 系统从 1970-01-01 00:00:00 开始计时,这个时间也称之为 Epoch Time,后续使用 Unix 的这种计时方式。
+
+## 具体使用
+
+Joda time 依赖 JDK5 及后续版本,没有额外的依赖。
+
+为了起到对比的效果,挑几个比较常用的场景进行对比:
+
+* 获取 1970 至今的毫秒数
+* 获取当前时间
+* 获取年、月、日、星期几
+* 日期的增减
+* 日期的格式化
+
+在代码中,经常会使用这个功能来表示唯一性:
+
+Joda time:
+
+```
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+<span class="hljs-keyword">long</span> mills = dt.getMillis();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Java time:
+
+```
+Clock clock = Clock.systemDefaultZone();
+<span class="hljs-keyword">long</span> mills = clock.millis();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+这块两个库没有太大的差异:
+
+Joda time:
+
+```
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+LocalDateTime localDateTime = dt.toLocalDateTime();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Java time:
+
+```
+LocalDateTime localDateTime = LocalDateTime.now();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Joda time:
+
+```
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+<span class="hljs-keyword">int</span> dayOfYear = dt.getDayOfYear();
+<span class="hljs-keyword">int</span> dayOfMonth = dt.getDayOfMonth();
+<span class="hljs-keyword">int</span> dayOfWeek = dt.getDayOfWeek();
+<span class="hljs-keyword">int</span> hourOfDay = dt.getHourOfDay();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Java time:
+
+```
+Clock clock = Clock.systemDefaultZone();
+LocalDateTime localDateTime = LocalDateTime.now(clock);
+<span class="hljs-keyword">int</span> dayOfYear = localDateTime.getDayOfYear();
+<span class="hljs-keyword">int</span> dayOfMonth = localDateTime.getDayOfMonth();
+<span class="hljs-keyword">int</span> dayOfWeek = localDateTime.getDayOfWeek().getValue();
+<span class="hljs-keyword">int</span> hourOfDay = localDateTime.getHour();
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+获取这些值两个库也没有太大的差异,但是对于一些场景,比如我想获得 "星期四" 这个字符串。 在 Joda 库中,可以 `dt.dayOfWeek().getAsShortText(); // &#x661F;&#x671F;&#x56DB;` 这样获得。在 Java 中, `localDateTime.getDayOfWeek().name(); //THURSDAY` 只能获取到英文。
+
+Joda time 在本地化方面比 Java time做的更好。
+
+Joda time:
+
+```
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+dt = dt.plusDays(<span class="hljs-number">2</span>);
+dt = dt.plusHours(<span class="hljs-number">5</span>);
+dt = dt.minusDays(<span class="hljs-number">1</span>);
+dt = dt.minusHours(<span class="hljs-number">2</span>);
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Java time:
+
+```
+LocalDateTime localDateTime = LocalDateTime.now();
+localDateTime = localDateTime.plusDays(<span class="hljs-number">2</span>);
+localDateTime = localDateTime.plusHours(<span class="hljs-number">2</span>);
+localDateTime = localDateTime.minusDays(<span class="hljs-number">1</span>);
+localDateTime = localDateTime.minusHours(<span class="hljs-number">1</span>);
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+日期格式化是日常使用最频繁的功能,下面来对比一下这两者的区别。
+
+Joda time:
+
+```
+
+DateTimeFormatter formatter = DateTimeFormat.forPattern(<span class="hljs-string">"yyyy-MM-dd HH:mm:ss"</span>);
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+System.out.println(dt.toString(formatter));
+
+String dateFormat = <span class="hljs-string">"yyyy-MM-dd HH:mm:ss"</span>;
+System.out.println(dt.toString(dateFormat));
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Java time:
+
+```
+DateTimeFormatter formatter = DateTimeFormatter.ofPattern(<span class="hljs-string">"yyyy-MM-dd HH:mm:ss"</span>);
+LocalDateTime localDateTime = LocalDateTime.now();   System.out.println(formatter.format(localDateTime));
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+通过上面的对比,可以发现这两个类库都可以完成相同的功能。虽然在细节上是有一些细微的差别。
+
+java.util.Date 是 Java 中最早的日期类,后来就不推荐使用这个类了,java.util.Calendar 用来替代 Date。Calendar 有 Date 的所有功能,并且提供了更加丰富的获取年月日的 API。
+
+Calendar 是一个虚拟类,GregorianCalendar 则是 Calendar 的实现类。
+
+Java time 与 java.util 下的时间类相互转化,可以将 Date 或者 Calendar 转化成 Java time 中的 LocalDateTime.
+
+java.util.Date 转 java.time.LocalDateTime:
+
+```
+Date date = <span class="hljs-keyword">new</span> Date();
+LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+java.util.Carlendar 转 java.time.LocalDateTime:
+
+```
+Calendar calendar = Calendar.getInstance();
+LocalDateTime localDateTime = LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+Joda time 也可以与 java.util.Date 可以进行相互的转化:
+
+```
+
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+Date jdkDate = dt.toDate();
+
+dt = <span class="hljs-keyword">new</span> DateTime(jdkDate);
+
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+Calendar jdkCal = dt.toCalendar(Locale.CHINESE);
+
+dt = <span class="hljs-keyword">new</span> DateTime(jdkCal);
+
+DateTime dt = <span class="hljs-keyword">new</span> DateTime();
+GregorianCalendar jdkGCal = dt.toGregorianCalendar();
+
+dt = <span class="hljs-keyword">new</span> DateTime(jdkGCal);
+<span class="copy-code-btn">&#x590D;&#x5236;&#x4EE3;&#x7801;</span>
+```
+
+## 设计思想
+
+Joda time 与 Java time 在功能上已经相差不大,常用的功能这两个类库都可以完成,而且两个库都是线程安全的。
+
+但我认为 Joda time 的 API 更加简洁一些,Joda time 的使用可以直接从 DateTime 这个类开始。而 Java time 的使用则更加繁琐。
+
+从设计上来说 Java time 都不再使用 new 来创建实例,而是使用工厂方法来创建实例。这点上比 Joda time 的设计要更好,而且更加安全。
+
+既然 Joda time 都推荐迁移回 Java time 了,那么最终肯定是要迁移的。但是目前来说,我觉得 Joda time 用起来更加顺手一些,暂时还会继续使用这个。

File diff suppressed because it is too large
+ 321 - 0
_posts/limit-request.md


File diff suppressed because it is too large
+ 53 - 0
_posts/zk-1.md


+ 4 - 0
about/index.md

@@ -0,0 +1,4 @@
+---
+title: about
+date: 2020-06-22 06:18:09
+---

+ 5 - 0
categories/index.md

@@ -0,0 +1,5 @@
+---
+title: categories
+type: categories
+date: 2020-06-22 06:18:11
+---

+ 5 - 0
tags/index.md

@@ -0,0 +1,5 @@
+---
+title: tags
+type: tags
+date: 2020-06-22 06:18:10
+---