## innerpeacez 查看完整档案

|    |

#### 个人动态

innerpeacez 发布了文章 · 1月13日

## 特殊密码锁

#### 题目

``````描述

011
000

1
``````

#### 解答

``````public class Test

public static void main(String[] args) {
String concurrent = "011";
String spec = "000";
two(concurrent, spec);
}

public static void two(String concurrent, String spec) {
Assert.assertTrue("Cannot be greater than 30", concurrent.length() <= 30);
String[] one = toArray(concurrent);
String[] two = toArray(spec);
if (one.length != two.length) {
System.out.println("impossible");
return;
}

Integer[] concurrentInts = toIntegers(one);
Integer[] specInts = toIntegers(two);
Integer count = 0;

for (int i = 0; i < concurrentInts.length - 1; i++) {
// 最后
if (i == concurrentInts.length - 2) {
if (concurrentInts[i] != specInts[i]) {
count++;
concurrentInts[concurrentInts.length - 2] = swap(concurrentInts[concurrentInts.length - 2]);
concurrentInts[concurrentInts.length - 1] = swap(concurrentInts[concurrentInts.length - 1]);
}
}

// 第一个位置和中间位置
if (concurrentInts[i] != specInts[i]) {
count++;
concurrentInts[i] = swap(concurrentInts[i + 1]);
concurrentInts[i+1] = swap(concurrentInts[i + 1]);
concurrentInts[i+2] = swap(concurrentInts[i + 2]);
}
}

if (Arrays.toString(concurrentInts).equals(Arrays.toString(specInts))) {
System.out.println(count);
} else {
System.out.println("impossible");
}
}

public static Integer[] toIntegers(String[] strs) {
Integer[] num = new Integer[strs.length];
for (int i = 0; i < num.length; i++) {
num[i] = Integer.parseInt(strs[i]);
}
return num;
}

public static Integer swap(Integer num) {
if (num == 0) {
num = 1;
}
if (num == 1) {
num = 0;
}
return num;
}

public static String[] toArray(String str) {
return str.split("");
}
}``````

innerpeacez 发布了文章 · 2019-12-30

## Helm Chart 一键部署 Jenkins

#### Jenkins

Jenkins是一款开源 CI&CD 软件，用于自动化各种任务，包括构建、测试和部署软件。目前提供超过1000个插件来支持构建、部署、自动化， 满足任何项目的需要。

Jenkins 支持各种运行方式，可通过系统包、Docker 或者通过一个独立的 Java 程序。本文记录通过使用 Helm Chart 将 Jenkins 部署到 Kubernetes 集群中

#### 本文环境

• jenkins 2.190.3
• Kubernetes v1.14.8
• helm 3.0 release

#### 部署

1. 部署 Kubernetes
2. 配置 helm 及 kubectl 环境
3. 部署 Jenkins

##### 部署 Jenkins
1. 添加 helm repo

``helm repo add stable https://kubernetes-charts.storage.googleapis.com/``
2. 查看目前的最近版本

``````\$ helm search repo stable/jenkins -l
NAME              CHART VERSION    APP VERSION    DESCRIPTION
stable/jenkins    1.9.11           lts            Open source continuous integration server. It s...
stable/jenkins    1.9.10           lts            Open source continuous integration server. It s...
stable/jenkins    1.9.9            lts            Open source continuous integration server. It s...
stable/jenkins    1.9.8            lts            Open source continuous integration server. It s...
stable/jenkins    1.9.7            lts            Open source continuous integration server. It s...
stable/jenkins    1.9.6            lts            Open source continuous integration server. It s...
stable/jenkins    1.9.5            lts            Open source continuous integration server. It s...
stable/jenkins    1.9.4            lts            Open source continuous integration server. It s...``````
3. 部署 jenkins

chart 中对应的镜像版本为 lts ,这个版本的镜像 jenkins 一直有在更新。所以我们只需要部署目前最新的 chart 即可，默认是没有指定 storageClass 的，需要指定。

``````\$ helm install jenkins stable/jenkins -n <namespace> \
--set persistence.storageClass=<storageClass>``````

注意：namespace 为命名空间， storageClass 为存储类

只需这一条命令 jenkins 就已经部署完成了，并且 chart 中默认安装了一些常用插件，比如 kubernetes 插件,并且生成了对应的配置，chart 真香：）

#### 总结

innerpeacez 发布了文章 · 2019-10-29

## 使用 Helm Chart 部署及卸载 istio

### 部署 istio

1.添加 istio 官方的 helm 仓库

``helm repo add istio   https://storage.googleapis.com/istio-release/releases/1.3.3/charts/``

2.是否添加成功

``helm search repo istio``
NAME CHART VERSION APP VERSION DESCRIPTION
istio/istio 1.3.3 1.3.3 Helm chart for all istio components
istio/istio-cni 1.3.3 1.3.3 Helm chart for istio-cni components
istio/istio-init 1.3.3 1.3.3 Helm chart to initialize Istio CRDs

3.创建 istio-system 命名空间

``kubectl create ns istio-system``

4.创建 istio 所需的 crd 文件

``helm install istio-init istio/istio-init -n istio-system``

5.检查 CRD 文件是否创建完成，输出为23

``kubectl get crds | grep 'istio.io' | wc -l``
23

6.部署 istio

``helm install istio istio/istio -n istio-system``

NAME: istio
LAST DEPLOYED: Thu Oct 24 12:05:06 2019
NAMESPACE: istio-system
STATUS: deployed
REVISION: 1
NOTES:
Thank you for installing Istio.

To get started running application with Istio, execute the following steps:

1. Label namespace that application object will be deployed to by the following command (take default namespace as an example)

kubectl label namespace default istio-injection=enabled
​ kubectl get namespace -L istio-injection

\$ kubectl apply -f <your-application>.yaml

https://istio.io/

### 卸载 istio

1.卸载 istio

``helm -n istio-system uninstall istio``

2.删除 istio crd 文件

``````helm -n istio-system uninstall istio-init

kubectl delete crd `kubectl get crd | grep istio| awk '{print \$1}'```````

### 一键部署及卸载 istio 的脚本

#### 部署脚本

``````#!/bin/bash

VERSION=\$1

STATUS_CMD=`echo \$?`
CHECK_REPO_CMD=`helm repo list | grep \$REPO | wc -l`
echo "\$STATUS_CMD"
echo "\$CHECK_REPO_CMD"
while [[ \$STATUS_CMD != 0 && \$CHECK_REPO_CMD -ge 1 ]]
do
sleep 5

STATUS_CMD=`echo \$?`
CHECK_REPO_CMD=`helm repo list | grep \$REPO | wc -l`
done
}

# Create istio-system namespace
create_namespace() {
NAMESPACE=\$1
kubectl create ns \${NAMESPACE}

STATUS_CMD=`echo \$?`
while [[ \$STATUS_CMD != 0 ]]
do
sleep 5
kubectl create ns \${NAMESPACE}
STATUS_CMD=`echo \$?`
done
}

# Create CRD need for istio
create_crd() {
NAMESPACE=\$1
helm install istio-init istio/istio-init -n \${NAMESPACE}
CRD_COUNT=`kubectl get crds | grep 'istio.i' | wc -l`

while [[ \${CRD_COUNT} != 23 ]]
do
sleep 5
CRD_COUNT=`kubectl get crds | grep 'istio.io' | wc -l`
done

echo 'Istio crd create successful'
}

# Deploy istio related components
deploy_istio() {
NAMESPACE=\$1
VERSION=\$2
helm install istio istio/istio -n \${NAMESPACE}

check() {
kubectl -n \${NAMESPACE}  get deploy | grep istio | awk '{print "deployment/"\$1}' | while read line ;
do
kubectl rollout status \$line -n \${NAMESPACE};
done
}
check

echo "Istio is deployed successful"
}

main(){
ISTIO_VERSION="1.3.3"
ISTIO_NAMESPACE="istio-system"
if [[ `kubectl get ns | grep \$ISTIO_NAMESPACE | wc -l ` == 0 && `kubectl get ns \$ISTIO_NAMESPACE | grep -v NAME | wc -l` == 0 ]] ;then
create_namespace \$ISTIO_NAMESPACE
fi
create_crd \$ISTIO_NAMESPACE
deploy_istio \$ISTIO_NAMESPACE \$ISTIO_VERSION
}

main``````

#### 卸载脚本

``````#!/bin/bash

helm -n istio-system uninstall istio
helm -n istio-system uninstall istio-init
kubectl delete crd `kubectl get crd | grep istio | awk '{print \$1}'`
kubectl delete ns istio-system``````

### 总结

innerpeacez 发布了文章 · 2019-10-08

## 使用 chart 部署 skywalking

### 使用 chart 部署 skywalking

• 使用 helm 2 提供的 helm serve 启动本地 helm repo
• 使用本地 chart 文件部署
• 使用 harbor 提供的 repo 功能
• 直接从官方 repo 进行部署

#### Helm 2 提供的 helm serve

##### 打包对应版本的 skywalking chart

1.配置 helm 环境，参考 Helm 环境配置 ，如果你要部署helm2 相关chart 可以直接配置 helm2 的相关环境

2.克隆/下载ZIP skywalking-kubernetes 这个仓库，仓库关于chart的目录结构如下

helm-chart

• helm2

• 6.0.0-GA
• 6.1.0
• helm3

• 6.3.0
• 6.4.0

``cd skywalking-kubernetes/helm-chart/<helm-version>/<skywalking-version>``

``cd skywalking-kubernetes/helm-chart/helm3/6.3.0``

3.由于skywalking 依赖 elasticsearch 作为存储库，执行以下命令更新依赖，默认会从官方repo进行拉取

``helm dep up skywalking``
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈Happy Helming!⎈
Saving 1 charts
Deleting outdated charts

``helm repo add stable https://kubernetes-charts.storage.googleapis.com``

4.打包 skywalking , 执行以下命令

``helm package skywalking/``
Successfully packaged chart and saved it to: C:codeinnerpeacez_githubskywalking-kuberneteshelm-charthelm36.3.0skywalking-0.1.0.tgz

`` ls``
skywalking/ skywalking-0.1.0.tgz
##### 启动 helm serve

``helm init``

``helm serve --address <ip>:8879 --repo-path /root/.helm/repository/local``

``curl ip:8879``
##### 部署 skywalking

1.在helm3 环境中添加启动的本地 repo

``helm repo add local http://<ip>:8879``

2.查看 skywalking chart 是否存在于本地仓库中

``helm search skywalking``
NAME CHART VERSION APP VERSION DESCRIPTION
local/skywalking 0.1.5 6.3.0 Apache SkyWalking APM System

3.部署

``helm -n test install skywalking local/skywalking``

#### 本地文件部署

``helm -n test install skywalking skywalking-0.1.0.tgz``

#### harbor 作为 repo 存储 charts

harbor 目前已经提供了，charts repo 的能力，这样就可以将 docker 镜像和 chart 存储在一个仓库中了，方便维护，具体harbor 的部署方法参考 Harbor 作为存储仓库存储 chart

#### 官方 repo 部署

``helm install -n test stable/skywalking``

### 总结

innerpeacez 发布了文章 · 2019-09-24

## 豆瓣电影TOP250和书籍TOP250爬虫

#### 豆瓣电影 TOP250 和书籍 TOP250 爬虫

##### 电影 TOP250 爬虫
``````import requests
from bs4 import BeautifulSoup
import time

def getlist(list_url):
time.sleep(2)
res = requests.get(list_url)
soup = BeautifulSoup(res.text, 'html.parser')
movie_list = soup.select('.grid_view li')
for m in movie_list:
rank = m.select('em')[0].text
score = m.select('.rating_num')[0].text
title = m.select('.title')[0].text
direct = m.select('.info .bd p')[0].text.strip()
actor = '\n主演:'.join(direct.split('   主演:'))
director = '年代:'.join(actor.split('                           '))
if m.select('.inq'):
else:
movie.append(
'排名: ' + rank + '\n'
+ '评分: ' + score + '\n'
+ '片名: ' + title + '\n'
+ director + '\n'
+ '评论: ' + comments + '\n'
+ '\n')
if soup.select('.next a'):
asoup = soup.select('.next a')[0]['href']
next_page = seed_url + asoup
getlist(next_page)
else:
print('结束')
return movie

def write(movies):
with open('movie.txt', 'w', encoding='utf8') as m:
for a in movies:
m.write(a)

def main():
write(getlist(seed_url))
pass

if __name__ == '__main__':
seed_url = 'https://movie.douban.com/top250'
movie = []
main()``````
##### 书籍 TOP250 爬虫
``````import bs4
import requests
import re
from bs4 import BeautifulSoup
from operator import itemgetter

def getHtmlText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""

def parserText(text, book_list):
soup = BeautifulSoup(text, 'html.parser')
for table in soup('table', {'width': '100%'}):
if isinstance(table, bs4.element.Tag):
tds = table.find('tr')('td')
divs = tds[1]('div')
content = {}
for div in divs:
if isinstance(div, bs4.element.Tag):
if div.find('a'):
name = div.find('a').attrs['title']
content.update({"书名": name})
if div.select('.rating_nums'):
score = div.select('.rating_nums')[0].text
content.update({"评分": score})
if div.select('.pl'):
people_num = div.select('.pl')[0].text
regex = re.compile(r'[\d]{1,10}')
content.update({"评价人数": regex.findall(people_num)[0]})

ps = tds[1]('p')
for p in ps:
if isinstance(p, bs4.element.Tag):
if p.attrs['class'][0] == 'quote':
description = p.find('span').string
content.update({"介绍": description})
if p.attrs['class'][0] == 'pl':
author = p.string
content.update({"作者信息": author})

book_list.append(content)

next_books = soup.find('span', {'class': 'next'})
if next_books.find('a'):
a = next_books.find('a').attrs['href']
text = getHtmlText(a)
parserText(text, books)

return book_list

def sortedBookTop250(book_list):
tmp = sorted(book_list, key=itemgetter('评分'), reverse=True)
for i in range(len(tmp)):
tmp[i].update({"排名": i + 1})
return tmp

def writeToFile(book_list):
with open('good_books.txt', 'w', encoding='utf8') as book_file:
for book in book_list:
for key, value in book.items():
book_file.write(f'{key}:{value}\n')
book_file.write('\n')
pass

def main():
text = getHtmlText(seed_url)
book_list = parserText(text, books)
writeToFile(sortedBookTop250(book_list))
pass

if __name__ == '__main__':
seed_url = "https://book.douban.com/top250"
books = []
main()``````

#### 总结

innerpeacez 发布了文章 · 2019-08-30

## 如何使用 Skywalking Agent ？

#### 三种方式：

• 使用官方提供的基础镜像
• 将 agent 包构建到已经存在的基础镜像中
• sidecar 模式挂载 agent

##### 2.将 agent 包构建到已经存在的基础镜像中

• 下载 oracle jdk

这个现在 oracle 有点恶心了，wget 各种不行，然后我放弃了，直接从官网下载了

• 下载 skywalking 官方发行包，并解压（以6.3.0为例）

``wget https://www.apache.org/dyn/closer.cgi/skywalking/6.3.0/apache-skywalking-apm-6.3.0.tar.gz && tar -zxvf apache-skywalking-apm-6.3.0.tar.gz``
• 通过以下 dockerfile 构建基础镜像

``````FROM alpine:3.8

ENV LANG=C.UTF-8

RUN set -eux && \
apk update && apk upgrade && \
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub &&\
apk --no-cache add unzip vim curl git bash ca-certificates glibc-2.30-r0.apk file && \
rm -rf /var/lib/apk/* &&\
mkdir -p /usr/skywalking/agent/

# A streamlined jre

# set env
ENV JAVA_HOME /usr/java/jdk1.8.0_221
ENV PATH \${PATH}:\${JAVA_HOME}/bin

# run container with base path:/
WORKDIR /

CMD bash``````

##### 3.sidecar 模式挂载 agent

• 下载skywalking 官方发行包，并解压

``wget https://www.apache.org/dyn/closer.cgi/skywalking/6.3.0/apache-skywalking-apm-6.3.0.tar.gz && tar -zxvf apache-skywalking-apm-6.3.0.tar.gz``
• 通过以下 dockerfile 进行构建

``````FROM busybox:latest

ENV LANG=C.UTF-8

RUN set -eux && mkdir -p /usr/skywalking/agent/

WORKDIR /``````

``````apiVersion: apps/v1
kind: Deployment
labels:
name: demo-sw
name: demo-sw
spec:
replicas: 1
selector:
matchLabels:
name: demo-sw
template:
labels:
name: demo-sw
spec:
initContainers:
- image: innerpeacez/sw-agent-sidecar:latest
name: sw-agent-sidecar
imagePullPolicy: IfNotPresent
command: ['sh']
args: ['-c','mkdir -p /skywalking/agent && cp -r /usr/skywalking/agent/* /skywalking/agent']
volumeMounts:
- mountPath: /skywalking/agent
name: sw-agent
containers:
- image: nginx:1.7.9
name: nginx
volumeMounts:
- mountPath: /usr/skywalking/agent
name: sw-agent
ports:
- containerPort: 80
volumes:
- name: sw-agent
emptyDir: {}``````

#### 总结

innerpeacez 发布了文章 · 2019-07-30

## Windows 使用 helm3 和 kubectl

### 本文环境

• kubernetes 1.15
• helm 3 alpha.2
• kubectl

#### Helm 3 是什么？

helm 是 kubernetes 官方的包管理工具, 通过 helm 将发布在 kubenetes 环境的多个 yaml 以软件包(charts)的形式打包，简化了 kubernetes 集群环境中应用的部署及更新,helm 支持应用的部署,升级，回滚等操作。helm 3 是针对于 helm 来说的升级版，做了一个功能上的调整，以其 github 发布的版本号命名，目前最新的版本为 Helm v3.0.0-alpha.2。个人认为helm 必定会成为未来 CICD 链中的关键一环。

#### 调教经历

##### 安装helm3

1.下载 helm3 windows 安装包，解压之后，你会看到有个 windows-amd64 的文件夹，其中有个 helm.exe 的可执行文件，我将这个文件夹直接放在了 `C:\windows-amd64`

2.设置 path

1. helm init

``````apiVersion: v1
generated: "2019-07-23T09:39:54.849920932+08:00"
repositories:
- caFile: ""
cache: C:\Users\innerpeacez\.helm\repository\cache\stable-index.yaml
certFile: ""
keyFile: ""
name: stable

#### 安装 kubectl

2.设置path

3.配置 kubernetes config 文件，这个文件是你在 linux 服务器上使用 kubectl 与kubernetes 交互的配置文件，我们只要在 linux 上找到 `\$HOME/.kube/config` 文件，将其复制到windows 的`\$HOME/.kube/config` ,即可，我的位置是 `C:\Users\innerpeacez\.kube\config`

4.测试 kubectl

#### 通过 helm 部署应用到 kubernetes 中

``kubectl config current-context``

``kubectl config set-context <current-context> --namespace test``

``helm -n test install promethues .\prometheus\``

NAME: promethues
LAST DEPLOYED: 2019-07-27 15:53:30.4257149 +0800 CST m=+0.775545401
NAMESPACE: test
STATUS: deployed

NOTES:
The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:

.......

#### 总结

innerpeacez 发布了文章 · 2019-07-30

## Windows 使用 helm3 和 kubectl

### 本文环境

• kubernetes 1.15
• helm 3 alpha.2
• kubectl

#### Helm 3 是什么？

helm 是 kubernetes 官方的包管理工具, 通过 helm 将发布在 kubenetes 环境的多个 yaml 以软件包(charts)的形式打包，简化了 kubernetes 集群环境中应用的部署及更新,helm 支持应用的部署,升级，回滚等操作。helm 3 是针对于 helm 来说的升级版，做了一个功能上的调整，以其 github 发布的版本号命名，目前最新的版本为 Helm v3.0.0-alpha.2。个人认为helm 必定会成为未来 CICD 链中的关键一环。

#### 调教经历

##### 安装helm3

1.下载 helm3 windows 安装包，解压之后，你会看到有个 windows-amd64 的文件夹，其中有个 helm.exe 的可执行文件，我将这个文件夹直接放在了 `C:\windows-amd64`

2.设置 path

1. helm init

``````apiVersion: v1
generated: "2019-07-23T09:39:54.849920932+08:00"
repositories:
- caFile: ""
cache: C:\Users\innerpeacez\.helm\repository\cache\stable-index.yaml
certFile: ""
keyFile: ""
name: stable

#### 安装 kubectl

2.设置path

3.配置 kubernetes config 文件，这个文件是你在 linux 服务器上使用 kubectl 与kubernetes 交互的配置文件，我们只要在 linux 上找到 `\$HOME/.kube/config` 文件，将其复制到windows 的`\$HOME/.kube/config` ,即可，我的位置是 `C:\Users\innerpeacez\.kube\config`

4.测试 kubectl

#### 通过 helm 部署应用到 kubernetes 中

``kubectl config current-context``

``kubectl config set-context <current-context> --namespace test``

``helm -n test install promethues .\prometheus\``

NAME: promethues
LAST DEPLOYED: 2019-07-27 15:53:30.4257149 +0800 CST m=+0.775545401
NAMESPACE: test
STATUS: deployed

NOTES:
The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:

.......

#### 总结

innerpeacez 发布了文章 · 2019-07-26

## Helm 3 使用 harbor 作为仓库存储 charts

#### Helm 3 新特性

• 移除了 Tiller
• 不同的 namespace 可以使用相同的 Release Name
• 简化模板对象 `.Capabilities`
• 使用`JSONSchema`验证 charts 的 Values
• `requirements.yaml`合并到`Chart.yaml`
• helm install 时需要指定 Release Name，开启自动生成需要 `--generate-name` 参数
• 支持 push 到远端 registry （如：harbor）
• 移除 helm serve
• 命令行变化（将原先的命令保留为别名Aliases）

• `helm delete` --> `helm uninstall`
• `helm inspect` -> `helm show`
• `helm fetch` -> `helm pull`
• go 导入路径改变 `k8s.io/helm` --> `helm.sh/helm`

#### Harbor v1.6.0 新特性

• 支持存储 helm charts
• ...

#### 调教开始

##### 环境
• kubernetes 1.10+
• helm 3
• harbor 1.6+
##### 调教步骤
1. 确保kubernetes环境可用
2. 下载并初始化 helm 3
3. 安装 harbor 1.6+
4. 添加 harbor 中的 chartrepo 到 helm 3 中
5. 安装使用 helm-push 插件

###### 2.下载并初始化 helm 3

``````wget https://get.helm.sh/helm-v2.14.2-linux-amd64.tar.gz
tar zxvf helm-v2.14.2-linux-amd64.tar.gz
cd linux-amd64
cp helm /usr/local/bin``````

``helm init``

###### 3.安装 harbor 1.6+

``helm repo add goharbor https://helm.goharbor.io``

``kubectl config current-context``

``kubectl config set-context <current-context> --namespace test``

``helm -n test install harbor goharbor/harbor --set persistence.enabled=false --set expose.type=nodePort --set expose.tls.enabled=false --set externalURL=http://192.168.10.196:30002``

• persistence.enabled=false 关闭存储，为了方便操作，真实使用时需要挂在存储
• expose.type=nodePort 使用 NodePort 访问
• expose.tls.enabled=false 关闭tls
• externalURL=http://192.168.10.196:30002 设置登录 harbor 的外部链接

``````NAME: harbor
LAST DEPLOYED: 2019-07-23 11:00:38.525597536 +0800 CST m=+0.690703892
NAMESPACE: test
STATUS: deployed

NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://core.harbor.domain.
For more details, please visit https://github.com/goharbor/harbor.``````
###### 4.添加 harbor 中的 chartrepo 到 helm 3 中

harbor 装好之后，我们访问 http://192.168.10.196:30002 进行登录 harbor, harbor 的默认账号密码是 admin/Harbor12345

``helm repo add test http://192.168.10.76:30002/chartrepo/chart_repo``
###### 5.安装使用 helm-push 插件
``helm plugin install https://github.com/chartmuseum/helm-push``

``helm push grafana-0.0.2.tgz test --username test --password xxx``

#### 参考

innerpeacez 发布了文章 · 2019-07-26

## Helm 3 使用 harbor 作为仓库存储 charts

#### Helm 3 新特性

• 移除了 Tiller
• 不同的 namespace 可以使用相同的 Release Name
• 简化模板对象 `.Capabilities`
• 使用`JSONSchema`验证 charts 的 Values
• `requirements.yaml`合并到`Chart.yaml`
• helm install 时需要指定 Release Name，开启自动生成需要 `--generate-name` 参数
• 支持 push 到远端 registry （如：harbor）
• 移除 helm serve
• 命令行变化（将原先的命令保留为别名Aliases）

• `helm delete` --> `helm uninstall`
• `helm inspect` -> `helm show`
• `helm fetch` -> `helm pull`
• go 导入路径改变 `k8s.io/helm` --> `helm.sh/helm`

#### Harbor v1.6.0 新特性

• 支持存储 helm charts
• ...

#### 调教开始

##### 环境
• kubernetes 1.10+
• helm 3
• harbor 1.6+
##### 调教步骤
1. 确保kubernetes环境可用
2. 下载并初始化 helm 3
3. 安装 harbor 1.6+
4. 添加 harbor 中的 chartrepo 到 helm 3 中
5. 安装使用 helm-push 插件

###### 2.下载并初始化 helm 3

``````wget https://get.helm.sh/helm-v2.14.2-linux-amd64.tar.gz
tar zxvf helm-v2.14.2-linux-amd64.tar.gz
cd linux-amd64
cp helm /usr/local/bin``````

``helm init``

###### 3.安装 harbor 1.6+

``helm repo add goharbor https://helm.goharbor.io``

``kubectl config current-context``

``kubectl config set-context <current-context> --namespace test``

``helm -n test install harbor goharbor/harbor --set persistence.enabled=false --set expose.type=nodePort --set expose.tls.enabled=false --set externalURL=http://192.168.10.196:30002``

• persistence.enabled=false 关闭存储，为了方便操作，真实使用时需要挂在存储
• expose.type=nodePort 使用 NodePort 访问
• expose.tls.enabled=false 关闭tls
• externalURL=http://192.168.10.196:30002 设置登录 harbor 的外部链接

``````NAME: harbor
LAST DEPLOYED: 2019-07-23 11:00:38.525597536 +0800 CST m=+0.690703892
NAMESPACE: test
STATUS: deployed

NOTES:
Please wait for several minutes for Harbor deployment to complete.
Then you should be able to visit the Harbor portal at https://core.harbor.domain.
For more details, please visit https://github.com/goharbor/harbor.``````
###### 4.添加 harbor 中的 chartrepo 到 helm 3 中

harbor 装好之后，我们访问 http://192.168.10.196:30002 进行登录 harbor, harbor 的默认账号密码是 admin/Harbor12345

``helm repo add test http://192.168.10.76:30002/chartrepo/chart_repo``
###### 5.安装使用 helm-push 插件
``helm plugin install https://github.com/chartmuseum/helm-push``

``helm push grafana-0.0.2.tgz test --username test --password xxx``

#### 参考

innerpeacez 发布了文章 · 2019-07-19

## Spring Boot 配置多源的 RabbitMQ

#### 简介

`MQ` 是开发中很平常的中间件，本文讲述的是怎么在一个`Spring Boot`项目中配置多源的`RabbitMQ`，这里不过多的讲解`RabbitMQ`的相关知识点。如果你也有遇到需要往多个`RabbitMQ`中发送消息的需求，希望本文可以帮助到你。

#### 环境

• rabbitmq 3.7.12
• spring boot 2.1.6.RELEASE

#### SpringBoot中配置两个RabbitMQ源

##### 代码：
``````/**
* @author innerpeacez
* @since 2019/3/11
*/
@Data
public abstract class AbstractRabbitConfiguration {

protected String host;
protected int port;

protected ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(port);
return connectionFactory;
}
}``````

``````package com.zhw.study.springbootmultirabbitmq.config;

import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
* @author innerpeacez
* @since 2019/3/8
*/

@Configuration
@ConfigurationProperties("spring.rabbitmq.first")
public class FirstRabbitConfiguration extends AbstractRabbitConfiguration {

@Bean(name = "firstConnectionFactory")
@Primary
public ConnectionFactory firstConnectionFactory() {
return super.connectionFactory();
}

@Bean(name = "firstRabbitTemplate")
@Primary
public RabbitTemplate firstRabbitTemplate(@Qualifier("firstConnectionFactory") ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}

@Bean(name = "firstFactory")
public SimpleRabbitListenerContainerFactory firstFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer,
@Qualifier("firstConnectionFactory") ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}

}
}``````

``````package com.zhw.study.springbootmultirabbitmq.config;

import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author innerpeacez
* @since 2019/3/8
*/

@Configuration
@ConfigurationProperties("spring.rabbitmq.second")
public class SecondRabbitConfiguration extends AbstractRabbitConfiguration {

@Bean(name = "secondConnectionFactory")
public ConnectionFactory secondConnectionFactory() {
return super.connectionFactory();
}

@Bean(name = "secondRabbitTemplate")
public RabbitTemplate secondRabbitTemplate(@Qualifier("secondConnectionFactory") ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}

@Bean(name = "secondFactory")
public SimpleRabbitListenerContainerFactory secondFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer,
@Qualifier("secondConnectionFactory") ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}

}
}``````

``````spring:
application:
name: multi-rabbitmq
rabbitmq:
first:
host: 192.168.10.76
port: 30509
second:
host: 192.168.10.76
port: 31938
##### 测试

``````/**
* @author innerpeacez
* @since 2019/3/8
*/
@Component
public abstract class MultiRabbitTemplate {

@Autowired
@Qualifier(value = "firstRabbitTemplate")
public AmqpTemplate firstRabbitTemplate;

@Autowired
@Qualifier(value = "secondRabbitTemplate")
public AmqpTemplate secondRabbitTemplate;
}``````

``````/**
* @author innerpeacez
* @since 2019/3/11
*/
@Component
@Slf4j
public class TestFirstSender extends MultiRabbitTemplate implements MessageSender {

@Override
public void send(Object msg) {
log.info("rabbitmq1 , msg: {}", msg);
firstRabbitTemplate.convertAndSend("rabbitmq1", msg);
}

public void rabbitmq1sender() {
this.send("innerpeacez1");
}
}``````

``````/**
* @author innerpeacez
* @since 2019/3/11
*/
@Component
@Slf4j
public class TestSecondSender extends MultiRabbitTemplate implements MessageSender {

@Override
public void send(Object msg) {
log.info("rabbitmq2 , msg: {}", msg);
secondRabbitTemplate.convertAndSend("rabbitmq2", msg);
}

public void rabbitmq2sender() {
this.send("innerpeacez2");
}
}``````

``````/**
* @author innerpeacez
* @since 2019/3/11
*/

@Slf4j
@Component
public class TestFirstConsumer implements MessageConsumer {

@Override
@RabbitListener(bindings = @QueueBinding(value = @Queue("rabbitmq1")
, exchange = @Exchange("rabbitmq1")
, key = "rabbitmq1")
, containerFactory = "firstFactory")
log.info("rabbitmq1 , {}", obj);
}

}``````
``````/**
* @author innerpeacez
* @since 2019/3/11
*/

@Slf4j
@Component
public class TestSecondConsumer implements MessageConsumer {

@Override
@RabbitListener(bindings = @QueueBinding(value = @Queue("rabbitmq2")
, exchange = @Exchange("rabbitmq2")
, key = "rabbitmq2")
, containerFactory = "secondFactory")
log.info("rabbitmq2 , {}", obj);
}

}``````

``````@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class SpringBootMultiRabbitmqApplicationTests extends MultiRabbitTemplate {

@Autowired
private TestFirstSender firstSender;
@Autowired
private TestSecondSender secondSender;

/**
* 一百个线程向 First Rabbitmq 的 rabbitmq1 queue中发送一百条消息
*/
@Test
public void testFirstSender() {
for (int i = 0; i < 100; i++) {
firstSender.rabbitmq1sender()
).start();
}
try {
} catch (InterruptedException e) {
e.printStackTrace();
}
}

/**
* 一百个线程向 Second Rabbitmq 的 rabbitmq2 queue中发送一百条消息
*/
@Test
public void testSecondSender() {
for (int i = 0; i < 100; i++) {
secondSender.rabbitmq2sender()
).start();
}
try {
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}``````

#### 总结

innerpeacez 发布了文章 · 2019-07-19

## linux 定时任务 crontabs 安装及使用方法

#### 安装 crontab

``yum install crontabs``

centos7 自带了我没有手动去装

#### 启动/关闭

``````service crond start // 启动服务
service crond stop // 关闭服务
service crond restart // 重启服务

#### 查看 crontab 服务是否已设置为开机启动

``systemctl list-unit-files | grep enable | grep crond``

#### 将 crontab 加入开机自动启动

``````chkconfig crond on
// 或者
systemctl enable crond.service``````

#### 查看 crontab 状态

``service crond status // 查看crontab服务状态``

#### 编写定时任务

• 命令格式
``````min hour day month dayofweek command
分  时   天    月    星期几      命令``````
​ min：每个小时的第几分钟执行该任务；取值范围0-59

​ hour：每天的第几个小时执行该任务；取值范围0-23

​ day：每月的第几天执行该任务；取值范围1-31

​ month：每年的第几个月执行该任务；取值范围1-12

​ dayofweek：每周的第几天执行该任务；取值范围0-6，0表示周末

​ command：指定要执行的命令

• 编辑命令两种方式

1. 在命令行输入: crontab -e 然后添加相应的任务，wq存盘退出
2. 直接编辑/etc/crontab 文件，即vi /etc/crontab，添加相应的任务
• 时间格式
​ * ：表示任意的时刻；如小时位 * 则表示每个小时

​ n ：表示特定的时刻；如小时位 5 就表示5时

​ n,m ：表示特定的几个时刻；如小时位 1,10 就表示1时和10时

​ n－m ：表示一个时间段；如小时位 1-5 就表示1到5点

/n : 表示每隔多少个时间单位执行一次；如小时位 /1 就表示每隔1个小时执行一次命令，也可以写成 1-23/1

#### 小栗子

``````* 1 * * * ~/clear_cache.sh ：从 1:00 到 1:59 每隔1分钟执行一次脚本
0 * * * * ~/clear_cache.sh ：每个小时的 0 分钟执行一次脚本
*/10 * * * * ~/clear_cache.sh ：每隔10分执行一次脚本``````

#### 清理系统cache的脚本

##### 代码：
``vim ~/clear_cache_logs.txt``
``````sudo sysctl -w vm.drop_caches=3
sudo sysctl -w vm.drop_caches=1
echo `date -R` >> ~/clear_cache_logs.txt
free -lh >> ~/clear_cache_logs.txt``````

innerpeacez 发布了文章 · 2019-07-11

## lombok

### 相识

lombok想必已经有很多人已经使用了很长时间了，而我却是第一次接触到，有点呆。lombok主要是用于减少重复代码，通过一组简单的注释取代一些重复的Java代码。对于lombok的评价褒贬不一，有的人觉得特别方便，有的人觉得改变了一成不变的代码结构，增加了代码维护成本（有的人没有用过lombok），我是觉得每一个工具诞生肯定是有他诞生的价值的，多学一个是一个啊，小老弟，用不用再说。：）

### 准备

#### 2、pom文件引入project lombok的maven依赖

``````<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>``````

lombok maven版本

### 注解介绍

#### @Getter和@Setter

``````public class LombokTest {
@Getter @Setter
private boolean flag;
}``````

lombok遵循了boolean类型的get方法的约定，我们来看一下编译后的代码（等效Java代码）吧。

``````public class LombokTest {
private boolean flag;

public LombokTest() {
}

public boolean isFlag() {
return this.flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}
}``````

``````public class LombokTest {
@Getter(AccessLevel.PUBLIC)
@Setter(AccessLevel.PROTECTED)
private String name;
}``````

``````public class LombokTest {
private String name;

public LombokTest() {
}

public String getName() {
return this.name;
}

protected void setName(String name) {
this.name = name;
}
}``````

AccessLevel枚举类的源代码。

``````public enum AccessLevel {
PUBLIC, // public
MODULE, // 编译后相当于 default
PROTECTED, // protected
PACKAGE, // default
PRIVATE, // private
NONE; // 不生成

private AccessLevel() {
}
}``````

``````@Getter(AccessLevel.MODULE)
@Setter(AccessLevel.PROTECTED)
public class LombokTest {
private String name;
private boolean flag;
}``````

``````public class LombokTest {
private String name;
private boolean flag;

public LombokTest() {
}

String getName() {
return this.name;
}

boolean isFlag() {
return this.flag;
}

protected void setName(String name) {
this.name = name;
}

protected void setFlag(boolean flag) {
this.flag = flag;
}
}``````

#### @NonNull

``````public class LombokTest {
@NonNull
@Setter
@Getter
private String name;

public LombokTest(@NonNull String name) {
this.name = name;
}
}``````

``````public class LombokTest {
@NonNull
private String name;

public LombokTest(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
} else {
this.name = name;
}
}

public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
} else {
this.name = name;
}
}

@NonNull
public String getName() {
return this.name;
}
}``````

#### @ToString

``````@ToString
public class LombokTest {
private String name;
private static String phone;
}``````

``````public class LombokTest {
private String name;
private static String phone;

public LombokTest() {
}

public String toString() {
return "YmlProperties(name=" + this.name + ")";
}
}``````

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface ToString {
boolean includeFieldNames() default true; // 生成toString()方法时默认为 name-value的形式，设置为false时 则 value的形式。

String[] exclude() default {}; // 不包含指定字段

String[] of() default {}; // 包含指定字段

boolean callSuper() default false; // 是否调用父类的toString()方法

boolean doNotUseGetters() default false; // 生成toString()方法是否直接访问字段，设置为true时直接访问字段（如：this.name），false时通过getter()方法进行访问(如：this.getName())。当然如果没有生成getter()方法，无论是否设置都直接访问字段

boolean onlyExplicitlyIncluded() default false; // 是否仅仅包含添加了@ToString.Include的字段，默认为false。

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude { // 使用@ToString.Exclude修饰字段，需要和@ToString注解一起使用，单独使用无效。
}

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {// 使用@ToString.Include修饰字段，需要和@ToString注解一起使用，单独使用无效。
int rank() default 0;

String name() default "";
}
}``````

• of和exclude属性设置多个字段时，以字符串数组的形式，如：
``````@ToString(of = {"name","phone"}) // 包含name和phone字段
@ToString(exclude = {"name","phone"}) // 不包含name和phone字段``````
• 使用@ToString.Include或者@ToString.Exclude注解时也需要使用@ToString注解，否者无效。
``````@ToString
public class LombokTest {
@ToString.Include
private String name;
@ToString.Exclude
private String phone;
}``````

#### @EqualsAndHashCode

``````@EqualsAndHashCode
public class LombokTest {
private String name;
private String phone;
private boolean flag;
}``````

``````public class LombokTest {
private String name;
private String phone;
private boolean flag;

public LombokTest() {
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else {
label39: {
Object this\$name = this.name;
Object other\$name = other.name;
if (this\$name == null) {
if (other\$name == null) {
break label39;
}
} else if (this\$name.equals(other\$name)) {
break label39;
}

return false;
}

Object this\$phone = this.phone;
Object other\$phone = other.phone;
if (this\$phone == null) {
if (other\$phone != null) {
return false;
}
} else if (!this\$phone.equals(other\$phone)) {
return false;
}

if (this.flag != other.flag) {
return false;
} else {
return true;
}
}
}
}

protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object \$name = this.name;
int result = result * 59 + (\$name == null ? 43 : \$name.hashCode());
Object \$phone = this.phone;
result = result * 59 + (\$phone == null ? 43 : \$phone.hashCode());
result = result * 59 + (this.flag ? 79 : 97);
return result;
}
}``````

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
String[] exclude() default {};

String[] of() default {};

boolean callSuper() default false;// 是否使用父类的equals和toString方法，注意：父类为Object时无法设置为true。

boolean doNotUseGetters() default false;

EqualsAndHashCode.AnyAnnotation[] onParam() default {};

boolean onlyExplicitlyIncluded() default false;

/** @deprecated */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation { // 过时的方法（deprecated）
}

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {
}

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
String replaces() default "";
}
}``````

#### @Data

``````@Data
public class LombokTest {
private String name;
private String phone;
private boolean flag;
}``````

``````public class LombokTest {
private String name;
private String phone;
private boolean flag;

public LombokTest() {
}

public String getName() {
return this.name;
}

public String getPhone() {
return this.phone;
}

public boolean isFlag() {
return this.flag;
}

public void setName(String name) {
this.name = name;
}

public void setPhone(String phone) {
this.phone = phone;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else {
label39: {
Object this\$name = this.getName();
Object other\$name = other.getName();
if (this\$name == null) {
if (other\$name == null) {
break label39;
}
} else if (this\$name.equals(other\$name)) {
break label39;
}

return false;
}

Object this\$phone = this.getPhone();
Object other\$phone = other.getPhone();
if (this\$phone == null) {
if (other\$phone != null) {
return false;
}
} else if (!this\$phone.equals(other\$phone)) {
return false;
}

if (this.isFlag() != other.isFlag()) {
return false;
} else {
return true;
}
}
}
}

protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object \$name = this.getName();
int result = result * 59 + (\$name == null ? 43 : \$name.hashCode());
Object \$phone = this.getPhone();
result = result * 59 + (\$phone == null ? 43 : \$phone.hashCode());
result = result * 59 + (this.isFlag() ? 79 : 97);
return result;
}

public String toString() {
return "LombokTest(name=" + this.getName() + ", phone=" + this.getPhone() + ", flag=" + this.isFlag() + ")";
}
}``````

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
String staticConstructor() default "";
}``````

``@Data(staticConstructor = "getLombokTest")``
``````private LombokTest() {
}

public static LombokTest getLombokTest() {
return new LombokTest();
}
// ...省略其他代码``````

#### @Cleanup

``````public class LombokTest {
public static void main(String[] args) throws Exception {
@Cleanup InputStream is = new FileInputStream(args[0]);
@Cleanup OutputStream os = new FileOutputStream(args[0]);
}
}``````

``````public class LombokTest {
public static void main(String[] args) throws Exception {
FileInputStream is = new FileInputStream(args[0]);

try {
OutputStream os = new FileOutputStream(args[0]);
if (Collections.singletonList(os).get(0) != null) {
os.close();
}
} finally {
if (Collections.singletonList(is).get(0) != null) {
is.close();
}
}
}
}``````

``````@Target({ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface Cleanup {
String value() default "close";
}``````

``````public static void main(String[] args) throws Exception {
@Cleanup(value = "available") InputStream is = new FileInputStream(args[0]);
@Cleanup OutputStream os = new FileOutputStream(args[0]);
}``````

#### @Synchronized

``````public class LombokTest {
@Synchronized
public void hello() {

}

@Synchronized
public static void helloWorld() {

}

private final Object world = new Object();

@Synchronized("world")
public void world() {

}
}``````

``````public class LombokTest {
private final Object \$lock = new Object[0];
private static final Object \$LOCK = new Object[0];
private final Object world = new Object();

public LombokTest() {
}

public void hello() {
Object var1 = this.\$lock;
synchronized(this.\$lock) {
;
}
}

public static void helloWorld() {
Object var0 = \$LOCK;
synchronized(\$LOCK) {
;
}
}

public void world() {
Object var1 = this.world;
synchronized(this.world) {
;
}
}
}``````

#### @SneakyThrows

``````public class LombokTest {
@SneakyThrows()
public void testSneakyThrows() {
throw new IllegalAccessException();
}

@SneakyThrows(IllegalAccessException.class)
public void testSneakyThrows2() {
throw new IllegalAccessException();
}
}``````

``````public class LombokTest {
public LombokTest() {
}

public void testSneakyThrows() {
try {
throw new IllegalAccessException();
} catch (Throwable var2) {
throw var2;
}
}

public void testSneakyThrows2() {
try {
throw new IllegalAccessException();
} catch (IllegalAccessException var2) {
throw var2;
}
}
}``````

• You can pass any number of exceptions to the `@SneakyThrows` annotation. If you pass no exceptions, you may throw any exception sneakily.

#### @NoArgsConstructor，@ RequiredArgsConstructor，@ AllArgsConstructor

@NoArgsConstructor 生成一个无参构造器。

@NoArgsConstructor注解源代码，另外两个注解的源码和这个很类似，就不贴出来了。

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {
String staticName() default ""; // 如果指定了相应字段，则私有化构造并生成一个静态的获取实例方法。

NoArgsConstructor.AnyAnnotation[] onConstructor() default {};

AccessLevel access() default AccessLevel.PUBLIC;

boolean force() default false;

/** @deprecated */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation { // 过时的（deprecated）
}
}``````

@ RequiredArgsConstructor 生成包含必须处理的字段的构造器，如：final修饰（必须初始化）、@NonNull注解修饰的。

``````@RequiredArgsConstructor
public class LombokTest {
private String name;
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
}``````

``````public class LombokTest {
private String name;
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;

public LombokTest(String finalFiled) {
this.finalFiled = finalFiled;
}
}``````

@ AllArgsConstructor 生成一个全参构造器，除static修饰的字段。@NonNull可以组合使用。

``````@AllArgsConstructor
public class LombokTest {
private String name;
@NonNull
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
}``````

``````public class LombokTest {
private String name;
@NonNull
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;

public LombokTest(String name, @NonNull String phone, boolean flag, String finalFiled) {
if (phone == null) {
throw new NullPointerException("phone is marked @NonNull but is null");
} else {
this.name = name;
this.phone = phone;
this.flag = flag;
this.finalFiled = finalFiled;
}
}
}``````

### 小结

innerpeacez 发布了文章 · 2019-07-11

## lombok

### 相识

lombok想必已经有很多人已经使用了很长时间了，而我却是第一次接触到，有点呆。lombok主要是用于减少重复代码，通过一组简单的注释取代一些重复的Java代码。对于lombok的评价褒贬不一，有的人觉得特别方便，有的人觉得改变了一成不变的代码结构，增加了代码维护成本（有的人没有用过lombok），我是觉得每一个工具诞生肯定是有他诞生的价值的，多学一个是一个啊，小老弟，用不用再说。：）

### 准备

#### 2、pom文件引入project lombok的maven依赖

``````<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>``````

lombok maven版本

### 注解介绍

#### @Getter和@Setter

``````public class LombokTest {
@Getter @Setter
private boolean flag;
}``````

lombok遵循了boolean类型的get方法的约定，我们来看一下编译后的代码（等效Java代码）吧。

``````public class LombokTest {
private boolean flag;

public LombokTest() {
}

public boolean isFlag() {
return this.flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}
}``````

``````public class LombokTest {
@Getter(AccessLevel.PUBLIC)
@Setter(AccessLevel.PROTECTED)
private String name;
}``````

``````public class LombokTest {
private String name;

public LombokTest() {
}

public String getName() {
return this.name;
}

protected void setName(String name) {
this.name = name;
}
}``````

AccessLevel枚举类的源代码。

``````public enum AccessLevel {
PUBLIC, // public
MODULE, // 编译后相当于 default
PROTECTED, // protected
PACKAGE, // default
PRIVATE, // private
NONE; // 不生成

private AccessLevel() {
}
}``````

``````@Getter(AccessLevel.MODULE)
@Setter(AccessLevel.PROTECTED)
public class LombokTest {
private String name;
private boolean flag;
}``````

``````public class LombokTest {
private String name;
private boolean flag;

public LombokTest() {
}

String getName() {
return this.name;
}

boolean isFlag() {
return this.flag;
}

protected void setName(String name) {
this.name = name;
}

protected void setFlag(boolean flag) {
this.flag = flag;
}
}``````

#### @NonNull

``````public class LombokTest {
@NonNull
@Setter
@Getter
private String name;

public LombokTest(@NonNull String name) {
this.name = name;
}
}``````

``````public class LombokTest {
@NonNull
private String name;

public LombokTest(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
} else {
this.name = name;
}
}

public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
} else {
this.name = name;
}
}

@NonNull
public String getName() {
return this.name;
}
}``````

#### @ToString

``````@ToString
public class LombokTest {
private String name;
private static String phone;
}``````

``````public class LombokTest {
private String name;
private static String phone;

public LombokTest() {
}

public String toString() {
return "YmlProperties(name=" + this.name + ")";
}
}``````

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface ToString {
boolean includeFieldNames() default true; // 生成toString()方法时默认为 name-value的形式，设置为false时 则 value的形式。

String[] exclude() default {}; // 不包含指定字段

String[] of() default {}; // 包含指定字段

boolean callSuper() default false; // 是否调用父类的toString()方法

boolean doNotUseGetters() default false; // 生成toString()方法是否直接访问字段，设置为true时直接访问字段（如：this.name），false时通过getter()方法进行访问(如：this.getName())。当然如果没有生成getter()方法，无论是否设置都直接访问字段

boolean onlyExplicitlyIncluded() default false; // 是否仅仅包含添加了@ToString.Include的字段，默认为false。

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude { // 使用@ToString.Exclude修饰字段，需要和@ToString注解一起使用，单独使用无效。
}

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {// 使用@ToString.Include修饰字段，需要和@ToString注解一起使用，单独使用无效。
int rank() default 0;

String name() default "";
}
}``````

• of和exclude属性设置多个字段时，以字符串数组的形式，如：
``````@ToString(of = {"name","phone"}) // 包含name和phone字段
@ToString(exclude = {"name","phone"}) // 不包含name和phone字段``````
• 使用@ToString.Include或者@ToString.Exclude注解时也需要使用@ToString注解，否者无效。
``````@ToString
public class LombokTest {
@ToString.Include
private String name;
@ToString.Exclude
private String phone;
}``````

#### @EqualsAndHashCode

``````@EqualsAndHashCode
public class LombokTest {
private String name;
private String phone;
private boolean flag;
}``````

``````public class LombokTest {
private String name;
private String phone;
private boolean flag;

public LombokTest() {
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else {
label39: {
Object this\$name = this.name;
Object other\$name = other.name;
if (this\$name == null) {
if (other\$name == null) {
break label39;
}
} else if (this\$name.equals(other\$name)) {
break label39;
}

return false;
}

Object this\$phone = this.phone;
Object other\$phone = other.phone;
if (this\$phone == null) {
if (other\$phone != null) {
return false;
}
} else if (!this\$phone.equals(other\$phone)) {
return false;
}

if (this.flag != other.flag) {
return false;
} else {
return true;
}
}
}
}

protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object \$name = this.name;
int result = result * 59 + (\$name == null ? 43 : \$name.hashCode());
Object \$phone = this.phone;
result = result * 59 + (\$phone == null ? 43 : \$phone.hashCode());
result = result * 59 + (this.flag ? 79 : 97);
return result;
}
}``````

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
String[] exclude() default {};

String[] of() default {};

boolean callSuper() default false;// 是否使用父类的equals和toString方法，注意：父类为Object时无法设置为true。

boolean doNotUseGetters() default false;

EqualsAndHashCode.AnyAnnotation[] onParam() default {};

boolean onlyExplicitlyIncluded() default false;

/** @deprecated */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation { // 过时的方法（deprecated）
}

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {
}

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
String replaces() default "";
}
}``````

#### @Data

``````@Data
public class LombokTest {
private String name;
private String phone;
private boolean flag;
}``````

``````public class LombokTest {
private String name;
private String phone;
private boolean flag;

public LombokTest() {
}

public String getName() {
return this.name;
}

public String getPhone() {
return this.phone;
}

public boolean isFlag() {
return this.flag;
}

public void setName(String name) {
this.name = name;
}

public void setPhone(String phone) {
this.phone = phone;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else {
label39: {
Object this\$name = this.getName();
Object other\$name = other.getName();
if (this\$name == null) {
if (other\$name == null) {
break label39;
}
} else if (this\$name.equals(other\$name)) {
break label39;
}

return false;
}

Object this\$phone = this.getPhone();
Object other\$phone = other.getPhone();
if (this\$phone == null) {
if (other\$phone != null) {
return false;
}
} else if (!this\$phone.equals(other\$phone)) {
return false;
}

if (this.isFlag() != other.isFlag()) {
return false;
} else {
return true;
}
}
}
}

protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}

public int hashCode() {
int PRIME = true;
int result = 1;
Object \$name = this.getName();
int result = result * 59 + (\$name == null ? 43 : \$name.hashCode());
Object \$phone = this.getPhone();
result = result * 59 + (\$phone == null ? 43 : \$phone.hashCode());
result = result * 59 + (this.isFlag() ? 79 : 97);
return result;
}

public String toString() {
return "LombokTest(name=" + this.getName() + ", phone=" + this.getPhone() + ", flag=" + this.isFlag() + ")";
}
}``````

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
String staticConstructor() default "";
}``````

``@Data(staticConstructor = "getLombokTest")``
``````private LombokTest() {
}

public static LombokTest getLombokTest() {
return new LombokTest();
}
// ...省略其他代码``````

#### @Cleanup

``````public class LombokTest {
public static void main(String[] args) throws Exception {
@Cleanup InputStream is = new FileInputStream(args[0]);
@Cleanup OutputStream os = new FileOutputStream(args[0]);
}
}``````

``````public class LombokTest {
public static void main(String[] args) throws Exception {
FileInputStream is = new FileInputStream(args[0]);

try {
OutputStream os = new FileOutputStream(args[0]);
if (Collections.singletonList(os).get(0) != null) {
os.close();
}
} finally {
if (Collections.singletonList(is).get(0) != null) {
is.close();
}
}
}
}``````

``````@Target({ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface Cleanup {
String value() default "close";
}``````

``````public static void main(String[] args) throws Exception {
@Cleanup(value = "available") InputStream is = new FileInputStream(args[0]);
@Cleanup OutputStream os = new FileOutputStream(args[0]);
}``````

#### @Synchronized

``````public class LombokTest {
@Synchronized
public void hello() {

}

@Synchronized
public static void helloWorld() {

}

private final Object world = new Object();

@Synchronized("world")
public void world() {

}
}``````

``````public class LombokTest {
private final Object \$lock = new Object[0];
private static final Object \$LOCK = new Object[0];
private final Object world = new Object();

public LombokTest() {
}

public void hello() {
Object var1 = this.\$lock;
synchronized(this.\$lock) {
;
}
}

public static void helloWorld() {
Object var0 = \$LOCK;
synchronized(\$LOCK) {
;
}
}

public void world() {
Object var1 = this.world;
synchronized(this.world) {
;
}
}
}``````

#### @SneakyThrows

``````public class LombokTest {
@SneakyThrows()
public void testSneakyThrows() {
throw new IllegalAccessException();
}

@SneakyThrows(IllegalAccessException.class)
public void testSneakyThrows2() {
throw new IllegalAccessException();
}
}``````

``````public class LombokTest {
public LombokTest() {
}

public void testSneakyThrows() {
try {
throw new IllegalAccessException();
} catch (Throwable var2) {
throw var2;
}
}

public void testSneakyThrows2() {
try {
throw new IllegalAccessException();
} catch (IllegalAccessException var2) {
throw var2;
}
}
}``````

• You can pass any number of exceptions to the `@SneakyThrows` annotation. If you pass no exceptions, you may throw any exception sneakily.

#### @NoArgsConstructor，@ RequiredArgsConstructor，@ AllArgsConstructor

@NoArgsConstructor 生成一个无参构造器。

@NoArgsConstructor注解源代码，另外两个注解的源码和这个很类似，就不贴出来了。

``````@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {
String staticName() default ""; // 如果指定了相应字段，则私有化构造并生成一个静态的获取实例方法。

NoArgsConstructor.AnyAnnotation[] onConstructor() default {};

AccessLevel access() default AccessLevel.PUBLIC;

boolean force() default false;

/** @deprecated */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation { // 过时的（deprecated）
}
}``````

@ RequiredArgsConstructor 生成包含必须处理的字段的构造器，如：final修饰（必须初始化）、@NonNull注解修饰的。

``````@RequiredArgsConstructor
public class LombokTest {
private String name;
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
}``````

``````public class LombokTest {
private String name;
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;

public LombokTest(String finalFiled) {
this.finalFiled = finalFiled;
}
}``````

@ AllArgsConstructor 生成一个全参构造器，除static修饰的字段。@NonNull可以组合使用。

``````@AllArgsConstructor
public class LombokTest {
private String name;
@NonNull
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
}``````

``````public class LombokTest {
private String name;
@NonNull
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;

public LombokTest(String name, @NonNull String phone, boolean flag, String finalFiled) {
if (phone == null) {
throw new NullPointerException("phone is marked @NonNull but is null");
} else {
this.name = name;
this.phone = phone;
this.flag = flag;
this.finalFiled = finalFiled;
}
}
}``````

### 小结

innerpeacez 关注了标签 · 2019-01-11

## java

Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言，是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台（即 JavaSE, JavaEE, JavaME）的总称。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

Java编程语言的风格十分接近 C++ 语言。继承了 C++ 语言面向对象技术的核心，Java舍弃了 C++ 语言中容易引起错误的指針，改以引用取代，同时卸载原 C++ 与原来运算符重载，也卸载多重继承特性，改用接口取代，增加垃圾回收器功能。在 Java SE 1.5 版本中引入了泛型编程、类型安全的枚举、不定长参数和自动装/拆箱特性。太阳微系统对 Java 语言的解释是：“Java编程语言是个简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言”。

### 版本历史

JDK 1.01996 年 1 月 23 日
JDK 1.11997 年 2 月 19 日
J2SE 1.2`Playground`1998 年 12 月 8 日
J2SE 1.3`Kestrel`2000 年 5 月 8 日
J2SE 1.4`Merlin`2002 年 2 月 6 日
J2SE 5.0 (1.5.0)`Tiger`2004 年 9 月 30 日
Java SE 6`Mustang`2006 年 11 月 11 日
Java SE 7`Dolphin`2011 年 7 月 28 日
Java SE 8`JSR 337`2014 年 3 月 18 日
##### 最新发布的稳定版本：
``````Java Standard Edition 8 Update 11 (1.8.0_11) - (July 15, 2014)
Java Standard Edition 7 Update 65 (1.7.0_65) - (July 15, 2014)``````

### 命名规范

Java 程序应遵循以下的 命名规则，以增加可读性，同时降低偶然误差的概率。遵循这些命名规范，可以让别人更容易理解你的代码。

• 类型名（类，接口，枚举等）应以大写字母开始，同时大写化后续每个单词的首字母。例如：`String``ThreadLocal``and NullPointerException`。这就是著名的帕斯卡命名法。
• 方法名 应该是驼峰式，即以小写字母开头，同时大写化后续每个单词的首字母。例如：`indexOf``printStackTrace``interrupt`
• 字段名 同样是驼峰式，和方法名一样。
• 常量表达式的名称`static final` 不可变对象）应该全大写，同时用下划线分隔每个单词。例如：`YELLOW``DO_NOTHING_ON_CLOSE`。这个规范也适用于一个枚举类的值。然而，`static final` 引用的非不可变对象应该是驼峰式。

### Hello World

``````public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}``````

``````javac -d . HelloWorld.java
java -cp . HelloWorld``````

Java 的源代码会被编译成可被 Java 命令执行的中间形式（用于 Java 虚拟机的字节代码指令）。

### 常见的问题

（待补充）

innerpeacez 关注了标签 · 2019-01-11

## 程序员

### 1024程序员节，中国程序员节

1024是2的十次方，二进制计数的基本计量单位之一。程序员(英文Programmer)是从事程序开发、维护的专业人员。程序员就像是一个个1024，以最低调、踏实、核心的功能模块搭建起这个科技世界。1GB=1024M，而1GB与1级谐音，也有一级棒的意思。

2015的10月24日，我们SegmentFault 也在5个城市同时举办黑客马拉松这个特殊的形式，聚集开发者开一个编程大爬梯。

### 特别推荐：

【SF 黑客马拉松】：http://segmentfault.com/hacka...
【1024程序员闯关秀】小游戏，欢迎来挑战 http://segmentfault.com/game/

• SF 开发者交流群：206236214
• 黑客马拉松交流群：280915731
• 开源硬件交流群：372308136
• Android 开发者交流群：207895295
• iOS 开发者交流群：372279630
• 前端开发者群：174851511

### 程序员相关问题集锦：

innerpeacez 关注了标签 · 2019-01-11

## vue.js

Reactive Components for Modern Web Interfaces.

Vue.js 是一个用于创建 web 交互界面的。其特点是

• 简洁 HTML 模板 + JSON 数据，再创建一个 Vue 实例，就这么简单。
• 数据驱动 自动追踪依赖的模板表达式和计算属性。
• 组件化 用解耦、可复用的组件来构造界面。
• 轻量 ~24kb min+gzip，无依赖。
• 快速 精确有效的异步批量 DOM 更新。
• 模块友好 通过 NPM 或 Bower 安装，无缝融入你的工作流。

innerpeacez 关注了标签 · 2019-01-11

## react.js

React (sometimes styled React.js or ReactJS) is an open-source JavaScript library for creating user interfaces that aims to address challenges encountered in developing single-page applications. It is maintained by Facebook, Instagram and a community of individual developers and corporations.

innerpeacez 关注了标签 · 2019-01-11

## python

Python（发音：英[ˈpaɪθən]，美[ˈpaɪθɑ:n]），是一种面向对象、直译式电脑编程语言，也是一种功能强大的通用型语言，已经具有近二十年的发展历史，成熟且稳定。它包含了一组完善而且容易理解的标准库，能够轻松完成很多常见的任务。它的语法非常简捷和清晰，与其它大多数程序设计语言不一样，它使用缩进来定义语句。

Python支持命令式程序设计、面向对象程序设计、函数式编程、面向切面编程、泛型编程多种编程范式。与Scheme、Ruby、Perl、Tcl等动态语言一样，Python具备垃圾回收功能，能够自动管理存储器使用。它经常被当作脚本语言用于处理系统管理任务和网络程序编写，然而它也非常适合完成各种高级任务。Python虚拟机本身几乎可以在所有的作业系统中运行。使用一些诸如py2exe、PyPy、PyInstaller之类的工具可以将Python源代码转换成可以脱离Python解释器运行的程序。

Python的主要参考实现是CPython，它是一个由社区驱动的自由软件。目前由Python软件基金会管理。基于这种语言的相关技术正在飞快的发展，用户数量快速扩大，相关的资源非常多。