Jason Lee Essay

Only dead fish go with the flow!

Jason Lee Essay

Java的类型通配符,可以出现在类、方法上面。最常用的方式就是集合类,例如List,Set等类上面。

通配符类型

  • 有泛型参数 List
  • 有无类型标识 List< ? >
  • 有通用的标识 List< object >
  • 边界通配符 List<? extends Class>
  • 边界通配符 List<? super Class>

本文主要讨论的是最后的关于边界的通配符类型。

看一个例子

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
public static void main(String[] args) {
List<B> bList = new ArrayList();
bList.add(new A());
bList.add(new B());
bList.add(new C());
A a3 = bList.get(0);
B b3 = bList.get(0);
C C3 = bList.get(0);

List<? extends B> bExtends = new ArrayList();
bExtends.add(new A());
bExtends.add(new B());
bExtends.add(new C());
A a1 = bExtends.get(0);
B b1 = bExtends.get(0);
C C1 = bExtends.get(0);

List<? super B> bSuper = new ArrayList();
bSuper.add(new A());
bSuper.add(new B());
bSuper.add(new C());
A a2 = bSuper.get(0);
B b2 = bSuper.get(0);
C C2 = bSuper.get(0);
}
}
class A {
String a = "a";
}
class B extends A {
String b = "b";
}
class C extends B {
String c = "c";
}

有三个类,继承关系是A < B < C。
然后声明了三个数组,list,extends,super.
上面的代码是编译不通过的。分别在第3、7、11-13、16、19、22-24行。

原理分析

List<? extends B> 得到的是B及B的子类的一个集合。
List<? super B> 得到的是B及B的父类的一个集合。
List 得到的是一个B的集合。

  1. ? extends B 声明了上界标识符、不定下界,而add(E e)的时候,编译器无法确定e需要分配的声明类型,虽然有实际类型,这个地方跟多态不一致,所以编译器不通过;而get(int i)的操作,会获取到一个肯定是B的元素,故是安全的。
  2. ? super B正相反,声明的是下界标识符、不定上界(Object),当add(E e)的时候,添加的是子类型,子类型向上转型是安全的;get(int i)的时候,并不能确定拿到的会是一个怎样的类型,可能是Object,也能是A,故也是违规的。
  3. B 声明的是上下界为B。add(E e)按照多态性,可以添加为B的类型及其子类型;get(int i)返回的必然是B的类型。

代码错误验证

按照第1条解释,第3、11-13行的错误符合解释。
按照第2条解释,第19、22-24行的错误符合解释。
第7、16行是由于向下转型是不安全的,股编译错误。

小结

extends和super别定义了上下限,结论如下面的表格

| | extends | super | T |
|—– |——— |——– |—— |
| add | unsafe | safe | safe |
| get | safe | unsafe | safe |

例子来源于《Kubernetes实践指南》一书。问题依然没有解决,求助大神。

测试环境

  • Centos 7.0
  • docker 1.13.1
  • kubectl v1.5.2
  • etcd 3.2.18
    都是通过yum安装,防火墙已关闭。

入坑问题

浏览器输入:http://ip:30001/demo/

Error:com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

相关资源rc、pod、service、ep都创建成功,但是myweb的pods无法访问到mysql提供的数据库服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# kubectl get all
NAME DESIRED CURRENT READY AGE
rc/mysql 1 1 1 4h
rc/myweb 1 1 1 2h

NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kubernetes 10.254.0.1 <none> 443/TCP 5d
svc/mysql 10.254.67.31 <none> 3306/TCP 4h
svc/myweb 10.254.62.177 <nodes> 8080:30001/TCP 2h

NAME READY STATUS RESTARTS AGE
po/mysql-vc9x6 1/1 Running 0 4h
po/myweb-6k7s3 1/1 Running 0 2h
# kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.1.171:6443 5d
mysql 172.17.0.4:3306 4h
myweb 172.17.0.2:8080 2h

定义文件

mysql-rc.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion : v1
kind : ReplicationController
metadata :
name : mysql
spec :
replicas : 1
selector :
app : mysql
template :
metadata :
labels :
app : mysql
spec :
containers :
- name : mysql
image : mysql
ports :
- containerPort : 3306
env :
- name : MYSQL_ROOT_PASSWORD
value : "123456"

mysql-svc.yaml

1
2
3
4
5
6
7
8
9
apiVersion : v1 
kind : Service
metadata :
name : mysql
spec :
ports :
- port : 3306
selector :
app : mysql

myweb-rc.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion : v1 
kind : ReplicationController
metadata :
name : myweb
spec :
replicas : 1
selector :
app : myweb
template :
metadata :
labels :
app : myweb
spec :
containers :
- name : myweb
image : tomcat-app:v1
ports :
- containerPort : 8080
env :
- name : MYSQL_SERVICE_HOST
value : 'mysql'
- name : MYSQL_SERVICE_PORT
value : '3306'

myweb-svc.yaml

1
2
3
4
5
6
7
8
9
10
11
apiVersion : v1 
kind : Service
metadata :
name : myweb
spec :
type : NodePort
ports :
- port : 8080
nodePort : 30001
selector :
app : myweb

启动方式是顺序执行kubectl create -f yaml

1
2
3
4
kubectl create -f mysql-rc.yaml
kubectl create -f mysql-svc.yaml
kubectl create -f myweb-rc.yaml
kubectl create -f myweb-svc.yaml

启动后即前面提到的问题。

查看源代码

既然无法建立连接,那先看下是如何建立连接的。登录到myweb的docker容器里面,查看index.jsp文件,主要内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
java.sql.Connection conn=null;
java.lang.String strConn;
java.sql.Statement stmt=null;
java.sql.ResultSet rs=null;
Class.forName("com.mysql.jdbc.Driver").newInstance();
try{
Class.forName("com.mysql.jdbc.Driver");
String ip=System.getenv("MYSQL_SERVICE_HOST");
String port=System.getenv("MYSQL_SERVICE_PORT");
ip=(ip==null)?"localhost":ip;
port=(port==null)?"3306":port;
System.out.println("Connecting to database...");

System.out.println("jdbc:mysql://"+ip+":"+port+"?useUnicode=true&characterEncoding=UTF-8");
conn = java.sql.DriverManager.getConnection("jdbc:mysql://"+ip+":"+port+"?useUnicode=true&characterEncoding=UTF-8", "root","123456");

stmt = conn.createStatement();
}catch(Exception ex){
...
}

就是用jsp创建了一个连接,连接的地址通过ENV方式注入。即在myweb-rc.yaml中配置的MYSQL_SERVICE_HOST和MYSQL_SERVICE_PORT环境变量指定。
既然指定名称为mysql无法解决,那换成mysql容器的IP是否可行呢?

更新配置

通过kubectl get ep 可以看到mysql暴露出的服务接口,那就用这个Ip试试。
修改myweb-rc.yaml:

1
2
3
env :
- name : MYSQL_SERVICE_HOST
value : '172.17.0.4'

然后重新部署pod。但是结果还是一样。

网上看来的

网上有个说法说把 MYSQL_SERVICE_HOST 去掉不配置。但是从源码看,不配置的默认值是localhost,显然不能具备3306的端口服务。

网络谜团

通过docker登录到容器内,互相ping网络都是通的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql:/# ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4): 56 data bytes
64 bytes from 172.17.0.4: icmp_seq=0 ttl=64 time=0.155 ms
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.139 ms
--- 172.17.0.4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.139/0.147/0.155/0.000 ms

myweb:/# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.062 ms
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.062/0.075/0.089/0.016 ms

很显然网络是互通,但不知为何无法通过端口访问。

clusterIP

除了ep暴露的端口服务外,还有一个ClusterIP存在,是否可以通过ClusterIP访问呢。

1
2
3
4
5
# kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kubernetes 10.254.0.1 <none> 443/TCP 5d
svc/mysql 10.254.67.31 <none> 3306/TCP 4h
svc/myweb 10.254.62.177 <nodes> 8080:30001/TCP 2h

发现ping ClusterIP全部都不通。至此不明白了。

三个IP

Kubernetes中管理主要有三种类型的IP:Pod IP 、Cluster IP 和 外部IP。

Pod IP

Kubernetes的最小部署单元是Pod。利用Flannel作为不同HOST之间容器互通技术时,由Flannel和etcd维护了一张节点间的路由表。Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。

每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:0.8.0的容器,容器内部与外部的通信经由此容器代理,该容器的IP也可以称为Pod IP。

Cluster IP

Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但Service Cluster IP就不一样了,没有网络设备为这个地址负责。它是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。

外部IP

Service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。

结论

依然不懂为什么会出现链接失败的情况,网络ping通的情况下,无法访问,这个坑填不上
怀疑方向:应该是配置层面的问题,可能是k8s的,也可能是docker的。

内容来自 https://help.sonatype.com/repomanager3/bower-repositories#BowerRepositories-BrowsingBowerRepositoriesandSearchingPackages
nexus3.0版本不仅提供了maven的私服,还可以托管docker、npm、bower甚至是python的仓库,为搭建统一的私服平台提供了便利。

Bower 仓库

* 1.简介
* 2.代理仓库
* 3.本地私服仓库
* 4.公开仓库组
* 5.安装bower
* 6.配置私服下载
* 7.浏览和检索依赖
* 8.上传bower包

简介

Bower是一个前端包管理工具。

NexusOSS是一个强大的Maven仓库管理器,它极大地简化了自己内部仓库的维护和外部仓库的访问。利用Nexus你可以只在一个地方就能够完全控制访问和部署在你所维护仓库中的每个Artifact。Nexus是一套“开箱即用”的系统不需要数据库,它使用文件系统加Lucene来组织数据。3.0版本之后加入了npm、bower、docker还有.net的仓库管理。

代理仓库

NexusOss可以对bower的外部仓库进行代理,比如代理官方库:https://registry.bower.io 。在官方库速度较慢的情况下非常好用。

创建bower代理库的步骤:

  • 选择创建repository,类型为bower(proxy)
  • 定义仓库名称:bower-proxy
  • 定义代理的仓库地址,例如官方仓库: https://registry.bower.io
  • 选择合适的存储

本地私服仓库

NexusOss支持创建本地私服用于管理bower包。私服仓库扮演了一个权威角色,定义包的URL和名称的关系。

创建本地私服仓库的操作步骤:

  • 选择创建repository,类型为bower(hosted)
  • 定义名称:bower-hosted
  • 选择合适的存储

公开仓库组

推荐使用仓库组暴露Bower仓库地址。仓库组既可以暴露多个代理仓库和多个本地私服仓库,当代理仓库或者私服变动的时候不会影响到使用者。

创建步骤如下:

  • 选择创建repository,类型为bower(group)
  • 定义名称:bower-all
  • 选择合适的存储
  • 添加bower-proxy和bower-hosted仓库到组中

    安装bower

    通过npm安装:
    1
    2
    3
    npm install -g bower 
    $ bower -v
    1.7.7
    使用Bower私服需要添加一个解析自定义URL的组件来完成解析NexusOss的工作。可以通过下面两种方式引入:
    1
    npm install -g bower-nexus3-resolver
    或者引入到package.json中
    1
    2
    3
    "devDependencies" : {
    "bower-nexus3-resolver" : "*"
    }

    配置私服下载

    一旦配置了Bower私服,就需要配置.bowerrc文件来实现到私服的URL解析。一般需要配置.bowerrc文件,可以配置全局的.bowerrc,位于$HOME目录下,也可以配置在项目内部的.bowerrc文件中。
    1
    2
    3
    4
    5
    6
    {
    "registry" : {
    "search" : [ "http://localhost:8081/repository/bower-all" ]
    },
    "resolvers" : [ "bower-nexus3-resolver" ]
    }
    测试下效果:
1
2
3
4
5
6
7
8
9
10
$ bower install jquery
bower jquery#*
not-cached nexus+http://localhost:8081/repository/bower-all/jquery#*
bower jquery#*
resolve nexus+http://localhost:8081/repository/bower-all/jquery#*
bower jquery#*
resolved nexus+http://localhost:8081/repository/bower-all/jquery#2.2.0
bower jquery#^2.2.0 install jquery#2.2.0

jquery#2.2.0 bower_components/jquery

浏览和检索依赖

NexusOSS提供了网页检索和浏览包,当然也可以通过Bower的命令行参数来检索。

上传bower包

发布Bower包,需要配置.bowerrc文件,制定register的位置;需要指定包的git路径。
1
2
3
4
5
6
7
8
9
{
"registry" : {
"search" : [
"http://192.168.1.62:8081/nexus/repository/bower-all"
],
"register" : "http://admin:admin123@192.168.1.62:8081/nexus/repository/bower-hosted"
},
"resolvers" : [ "bower-nexus3-resolver" ]
}
执行上传操作:
1
bower register example-package git://gitserver/project.git
测试安装:
1
bower install example-package

小结:

上次部分注意的是register的URL必须把授权参数填入,因为NexusOss侧需要权限验证,不写会一直报401的错误。

六一快乐!!!

什么是k8s,我不想解释,百度资料有很多,本系列只踩坑,不科普。

问题描述:

做Hello World的例子,结果get pods一直显示没有资源?

应用配置代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion : v1
kind : ReplicationController
metadata :
name : mysql
spec :
replicas : 2
selector :
app : mysql
template :
metadata :
labels :
app : mysql
spec :
containers :
- name : mysql
image : mysql
ports :
- containerPort : 3306
env :
- name : MYSQL_ROOT_PASSWORD
value : "123456"

创建rc

1
2
3
4
5
6
7
8
9
10
# kubectl create -f mysql-rc.yaml 
replicationcontroller "mysql" created
# kubectl get rc
NAME DESIRED CURRENT READY AGE
mysql 2 0 0 11s
myweb 2 0 0 5s
# kubectl get pods
No resources found.
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE

分析

创建了rc之后,虽然命令行提示成功了,但是pods一直没有创建,也检查了docker,mysql的镜像没有拉取。又仔细看了一边rc的结果,current和ready列的值是0,应该先解决current为0的问题。

google解决方案

  1. executed command :

    openssl genrsa -out /tmp/serviceaccount.ket 2048

  2. modified the /etc/kubernetes/apiserver file to add following :

    KUBE_API_ARGS=”–service_account_key_file=/tmp/serviceaccount.key”

  3. modified the /etc/kubernetes/controller-manager and add following: 

    KUBE_CONTROLLER_MANAGER_ARGS=”–service_account_private_key_file=/tmp/serviceaccount.key”

  4. restarted the kube-apiserver and kube-controller-manager services to restart the services
    1
    2
    service kube-apiserver restart
    service kube-controller-manager restart

参考:
https://blog.csdn.net/jinzhencs/article/details/51435020
https://github.com/kubernetes/kubernetes/issues/11355#issuecomment-127378691

git管理代码仓库的时候,会经常遇到这样的情况:

1
2
warning: CRLF will be replaced by LF in Test.java.
The file will have its original line endings in your working directory.

遇到上面的警告, 基本上都是将 autocrlf 设置为 false 解决,或者手动改变文件的CRLF属性。(IDEA具备这个功能,其他编辑器不知道)

什么是CRLF?

CRLF是Carriage-Return Line-Feed的缩写,意思是回车换行,就是回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)。

有什么不同?

  • CRLF->Windows-style
  • LF->Unix Style
  • CR->Mac Style

CRLF表示句尾使用回车换行两个字符(即我们常在Windows编程时使用”\r\n”换行)
LF表示表示句尾,只使用换行.
CR表示只使用回车.

git的三种模式

core.autocrlf有三种模式,分别对应三种转换情况。x代码换行符号,第一个是pull的转换情况,第二个是commit的时候情况。

  1. true: x -> LF -> CRLF
  2. input: x -> LF -> LF
  3. false: x -> x -> x

换行符=LF,autocrlf=true

如果你的源文件中是换行符是LF,而autocrlf=true, 此时git add就会遇到 fatal: LF would be replaced by CRLF 的错误。有两个解决办法:

  1. 将源文件中的LF转为CRLF即可【推荐】
  2. 将autocrlf 设置为 false

换行符=CRLF,autocrlf=input

如果你的源文件中是换行符是CRLF,而autocrlf=input, 此时git add也会遇到 fatal: CRLF would be replaced by LF 的错误。有两个解决办法:

  1. 将你源文件中的CRLF转为LF【推荐】
  2. 将autocrlf 设置为true 或者 false

我的建议:在Unix/Linux上设置 autocrlf = input, 在Windows上设置autocrlf = true(默认值)。

这样的话,
Windows:(true)
提交时,将CRLF 转成 LF再提交;
切出时,自动将LF 转为 CRLF;

Unix/Linux: (input)
提交时, 将CRLF 转成 LF再提交;
切出时,保持LF即可

这样即可保证仓库中永远都是LF. 而且在Windows工作空间都是CRLF, Unix/Linux工作空间都是LF.

core.autocrlf
假如你正在Windows上写程序,又或者你正在和其他人合作,他们在Windows上编程,而你却在其他系统上,在这些情况下,你可能会遇到行尾结束符问题。这是因为Windows使用回车和换行两个字符来结束一行,而Mac和Linux只使用换行一个字符。虽然这是小问题,但它会极大地扰乱跨平台协作。

Git可以在你提交时自动地把行结束符CRLF转换成LF,而在签出代码时把LF转换成CRLF。用core.autocrlf来打开此项功能,如果是在Windows系统上,把它设置成true,这样当签出代码时,LF会被转换成CRLF:

1
$ git config --global core.autocrlf true  

Linux或Mac系统使用LF作为行结束符,因此你不想 Git 在签出文件时进行自动的转换;当一个以CRLF为行结束符的文件不小心被引入时你肯定想进行修正,把core.autocrlf设置成input来告诉 Git 在提交时把CRLF转换成LF,签出时不转换:

1
$ git config --global core.autocrlf input  

这样会在Windows系统上的签出文件中保留CRLF,会在Mac和Linux系统上,包括仓库中保留LF。
如果你是Windows程序员,且正在开发仅运行在Windows上的项目,可以设置false取消此功能,把回车符记录在库中:

1
$ git config --global core.autocrlf false  

自定义的jar包提交到nexus的私服中,直接通过maven命令提交。

1
mvn clean source:jar deploy -X -DskipTests=true

参数解释:

  • clean 清空上次编译结果
  • deploy 发布到情况
  • source:jar 同步发布源码
  • -X debug级别日志输出
  • -DskipTests=true 跳过单元测试

执行的过程中出现一个错误:

1
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on project io: Failed to deploy artifacts: Could not transfer artifact cn.infisa:io:jar:1.0.2-RELEASE from/to releases (http://192.168.1.62:8081/nexus/content/repositories/releases/): Failed to transfer file: http://192.168.1.62:8081/nexus/content/repositories/releases/cn/infisa/io/1.0.2-RELEASE/io-1.0.2-RELEASE.jar. Return code is: 401, ReasonPhrase: Unauthorized. -> [Help 1]

原因: 本地用户提交releases或者snapshots里面,需要配置对应的权限,而且需要在settings.xml中配置。

1
2
3
4
5
<server>
<username>username</username>
<password>password</password>
<id>releases</id>
</server>

再次提交,成功通过。

有些时候会碰到这样的场景:java的功能里面要嵌入一个功能点,这个功能是通过是shell脚本实现的。这种时候就需要Java对脚本调用的支持了。

测试环境

Ubuntu16.04 i3-6100,12GB

Hello World

来看一个基本的例子

1
2
3
4
5
6
7
    Process exec = Runtime.getRuntime().exec(new String[] { "uname" ,"-a"});
exec.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(exec.getInputStream()));
System.out.println(reader.readLine());

Linux jason-Inspiron-3650 4.4.0-121-generic #145-Ubuntu SMP Fri Apr 13 13:47:23 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

解读Process

java.lang.Process类提供了获取输入、输出、等待执行和销毁进程的方法。
Process类可通过ProcessBuilder.start() 和 Runtime.exec 创建实例,从Java1.5开始,ProcessBuilder.start()是更推荐的做法,但网上的教程更多推荐用Runtime.exec()方法。

| Modifier and Type | Method | Description |
|———————— |———————- |————————————————————————————————————————– |
| abstract void | destroy () | Kills the subprocess. |
| abstract int | exitValue () | Returns the exit value for the subprocess. |
| abstract InputStream | getErrorStream () | Returns the input stream connected to the error output of the subprocess. |
| abstract InputStream | getInputStream () | Returns the input stream connected to the normal output of the subprocess. |
| abstract OutputStream | getOutputStream () | Returns the output stream connected to the normal input of the subprocess. |
| abstract int | waitFor () | Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. |

继承体系上面,Process的实现类是JDK内置的,linux版本的jdk中只带有一个实现类UnixProcess。

与脚本交互

Process不但可以执行进程,还可以获取进程的返回结果。

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
    private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
int exitCode = p.waitFor();
System.out.println(exitCode);
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(output.toString());
return output.toString();
}

PING www.a.shifen.com (111.13.100.91) 56(84) bytes of data.
64 bytes from localhost (111.13.100.91): icmp_seq=1 ttl=52 time=7.66 ms
64 bytes from localhost (111.13.100.91): icmp_seq=2 ttl=52 time=7.90 ms
64 bytes from localhost (111.13.100.91): icmp_seq=3 ttl=52 time=14.0 ms

--- www.a.shifen.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 7.668/9.861/14.013/2.937 ms

总结

Java 执行脚本的方式其实类似用直接在bash里面执行脚本,区别在于环境有些变动,执行的效果和bash基本一致。

Spring-boot包含众多的starter,每一个starter都包含了一个方面的最佳实践,比如spring-boot-starter-web包含了构建web应用的依赖框架,spring-boot-starter-logging包含了日志输出所需框架的合集。而本文的主角spring-boot-starter-actuator包含了metrics的相关工具集。

什么是actuator?

Spring Boot Actuator includes a number of additional features to help you monitor and manage your application when it’s pushed to production. You can choose to manage and monitor your application using HTTP or JMX endpoints. Auditing, health and metrics gathering can be automatically applied to your application. The user guide covers the features in more detail.
Spring Boot Actuator包含了一些额外的特性用于生产环境中监控和管理spring boot应用。actuator可以通过__HTTP__或者__JMX__对应用进行管控。可以自动收集审计、健康和度量信息。用户手册包含了更多的细节。

土话就是,线上应用都需要管控工具,省得大家再去造一个轮子了,spring-boot造好了一个,开箱即用,都到碗里来吧。

actuator的dependency分析

以1.5.4.RELEASE版本为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ mvn dependency:tree
[INFO] \- org.springframework.boot:spring-boot-starter-actuator:jar:1.5.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter:jar:1.5.4.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot:jar:1.5.4.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.4.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.4.RELEASE:compile
[INFO] | | +- ch.qos.logback:logback-classic:jar:1.1.11:compile
[INFO] | | | +- ch.qos.logback:logback-core:jar:1.1.11:compile
[INFO] | | | \- org.slf4j:slf4j-api:jar:1.7.22:compile
[INFO] | | +- org.slf4j:jcl-over-slf4j:jar:1.7.25:compile
[INFO] | | +- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] | | \- org.slf4j:log4j-over-slf4j:jar:1.7.25:compile
[INFO] | +- org.springframework:spring-core:jar:4.3.9.RELEASE:compile
[INFO] | \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] \- org.springframework.boot:spring-boot-actuator:jar:1.5.4.RELEASE:compile
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.8:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] | \- com.fasterxml.jackson.core:jackson-core:jar:2.8.8:compile
[INFO] \- org.springframework:spring-context:jar:4.3.9.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.3.9.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:4.3.9.RELEASE:compile
[INFO] \- org.springframework:spring-expression:jar:4.3.9.RELEASE:compile

核心依赖项目主要是spring-boot的相关基础组件和日志组件。

  • sfl4j和logback相关的都是日志类的组件。
  • jackson相关是json处理组件。
  • spring-context和beans,core,aop,expression这些是任何spring项目几乎都需要的组件
  • spring-boot还有spring-boot-autoconfig以及yaml是spring-boot的基础组建,提供默认配置和yml配置的解析支持。
  • spring-boot-actuator提供了监控的特性

开箱即用

在pom.xml中添加:

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.5.4.RELEASE</version>
</dependency>

然后直接启动就可以了,启动后可以查看最简单的http接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ curl localhost:8080/health
{
status: "UP",
diskSpace: {
status: "UP",
total: 196726059008,
free: 163859410944,
threshold: 10485760,
},
db: {
status: "UP",
database: "MySQL",
hello: 1,
},
}

git有个比较奇怪的问题,当目录或者文件名中出现了中文的时候,在执行git status 的时候,会返回一串unicode码,这段unicode码就读不懂了,必须解决。

git status显示unicode/乱码

1
2
3
$ git status
untracked file :
"\346\265\213\350\257\225/"

解决方法:

1
2
3
4
$ git config --global core.quotepath false
$ git status
untracked file :
测试/文件.md

解惑:

core.quotepath的作用是控制路径是否编码显示的选项。当路径中的字符大于0x80的时候,如果设置为true,转义显示;设置为false,不转义。

git commit log 中乱码

windows平台上面的问题比linux上面要更多。

1
2
3
4
5
$ git config --global gui.encoding utf-8

$ git config --global i18n.commitEncoding utf-8

$ git config --global gui.logOutputEncoding utf-8

以上基本可全部解决。

windows平台显示乱码

右键gitbash 选中“Options(选项)”-“text”.设置下面的locale为 zh_CN,Character Set 为UTF-8。
强烈推荐全部选用UTF-8,少用GBK。

0%