前言

上一节为springboot项目添加springboot-admin监控 学习了基于springboot1.5自己注册到admin的方法。接下来学习结合Eureka使用以及2.0的改变。

1.5spring-boot-admin集成eureka

我们继续上一节的项目修改,admin-server依赖修改如下

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
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>


<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

修改启动类,添加

1
2
@EnableDiscoveryClient
@EnableAdminServer

修改配置文件application.properties

1
2
3
4
server.port=8081
spring.application.name=admin-server
eureka.client.serviceUrl.defaultZone=${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/
management.security.enabled=false

注意,这里的eureka server要提前启动。具体细节,参见SpringCloud入门1-服务注册与发现(Eureka)

到这里就结束,可以直接启动。admin会自己拉取Eureka上注册的app信息,主动去注册。这也是唯一区别之前手动注册的地方,就是client端不需要admin-client的依赖,也不需要配置admin地址了,一切全部由admin-server自己实现。这样的设计对环境变化很友好,不用改了admin-server后去改所有app的配置了。

spring-boot-admin2.0的巨变

以为2.0比1.5区别不大,也确实不很大。关于client主动注册的部分没有变化。

这里,重新学习一遍,并添加上安全登录功能。

新建一个springboot项目

项目地址:

https://github.com/Ryan-Miao/spring-cloud-demo/tree/master/admin-server

添加spring-boot-admin-server, 最终pom依赖如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-boot-admin.version>2.0.0</spring-boot-admin.version>
<spring-cloud.version>Finchley.RC2</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<!--还没有发布-->
<!--<dependency>-->
<!--<groupId>de.codecentric</groupId>-->
<!--<artifactId>spring-boot-admin-server-cloud</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-dependencies</artifactId>
<version>${spring-boot-admin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>central</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<name>aliyun</name>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

注意到里面添加spring cloud eureka的依赖,我们也把admin给注册到eureka。

这次的配置文件比较复杂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
spring:
application:
name: admin-server
profiles:
active:
- secure


# tag::configuration-eureka[]
eureka: #<1>
instance:
leaseRenewalIntervalInSeconds: 10
health-check-url-path: /actuator/health #2.0后actuator的地址发生了变化
client:
registryFetchIntervalSeconds: 5
serviceUrl:
defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/

# 2.0开始,actuator默认不开放,所以要设置为开放
management:
endpoints:
web:
exposure:
include: "*" #<2>
endpoint:
health:
show-details: ALWAYS
server:
port: 8081
# end::configuration-eureka[]

---
spring:
profiles: insecure

---
# admin登录的用户名和密码
spring:
profiles: secure
security:
user:
name: "user"
password: "password"

# 注册给eureka的时候告诉eureka自己的密码
eureka:
instance:
metadata-map:
"user.name": ${spring.security.user.name} #These two are needed so that the server
"user.password": ${spring.security.user.password} #can access the protected client endpoints

首先,我们同时支持两种安全配置,一种没有安全认证,一种有。注意到前面的依赖pom里有security的依赖。针对security方案,需要配置用户名和密码。

其次,配置了eureka client相关参数,把自己注册到eureka里。

然后,关于actuator的端点接口,设置为全部开放。

最后,设置我们的用户名和密码,并把用户名和密码放到eureka里,方便识别。

配置security的安全过滤

最终的启动类如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

@EnableDiscoveryClient
@EnableAdminServer
@SpringBootApplication
public class AdminServerApplication {

public static void main(String[] args) {
SpringApplication.run(AdminServerApplication.class, args);
}

@Profile("insecure")
@Configuration
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()//
.and().csrf().disable();
}
}

@Profile("secure")
@Configuration
public static class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

private final String adminContextPath;

public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");

http.authorizeRequests()
.antMatchers(adminContextPath + "/assets/**").permitAll()
.antMatchers(adminContextPath + "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler)
.and()
.logout().logoutUrl(adminContextPath + "/logout").and()
.httpBasic().and()
.csrf().disable();
// @formatter:on
}
}
}

和之前没啥不同,唯一的区别是添加了安全认证相关的,即采用secure模式的时候必须输入用户名和密码。

启动

我们启动并选择激活配置环境secure

访问localhost:8081

详细页

界面确实比1.5好很多啊。

新建一个app来注册

依旧采用手动注册的方式,新建一个springboot项目,项目地址

https://github.com/Ryan-Miao/spring-cloud-demo/tree/master/provider-demo

首先,pom依赖要有eureka

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.test</groupId>
<artifactId>provider-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>provider-demo</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RC2</spring-cloud.version>
<spring-boot-admin.version>2.0.0</spring-boot-admin.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-dependencies</artifactId>
<version>${spring-boot-admin.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>central</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<name>aliyun</name>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>


</project>

注意,配置了eureka,用来注册。

依赖springfox-swagger2用来展示API。

spring-boot-admin-starter-client才是主动注册的核心库,用来发送注册申请。

需要再次强调了是build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

这里是为了生成版本信息,提供给spring-boot-admin展示。

provider-demo的配置文件

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
eureka:
instance:
leaseRenewalIntervalInSeconds: 10
health-check-url-path: /actuator/health
client:
registryFetchIntervalSeconds: 5
serviceUrl:
defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8761}/eureka/

management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS

server:
port: 8082

spring:
application:
name: provider-demo
boot:
admin:
client:
url: "http://localhost:8081"
password: password
username: user
instance:
prefer-ip: true

eureka的配置和admin-server相同,毕竟都是eureka的client嘛。不同的是这里没有开启spting security,所以不添加用户名和密码信息到meta-data里。

actuator同样需要暴露全部。

关于spring-boot-admin-client的注册配置里多了username和password,这个不是自己的,而是admin-server设置的,即前文的里的。

启动后就可以看到前面的详细信息了。

巨变在这里

在1.5版本里,我们只要加上eureka注册,就可以admin-server自动发现所有的app并自己注册监控了。但这里居然行不通了。我调试了几个小时,把依赖包翻来覆去研究了好多遍—-就是不行!!!

无奈,只好去github把spring-boot-admin的源码下载下来,找到注册的代码开始追踪。我发现,根本没有提供任何和eureka注册中心相关的代码。看到了spring-boot-admin-server-cloud, 进去看了源码,这里有关于注册中心的监听代码,也就是admin自动发现app的密码所在。那我把这个加入dependency不就好了吗,太年轻。加上后发现找不到版本。我说不应该啊,我有导入dependencyManagement的pom啊。手动指定版本也不行。最后无奈的发现,原来根本没有发布!!!

⚠️Note: Since Spring Cloud Finchley is not released yet, this version doesn’t include Spring Cloud Discovery support

所以,手动注册吧,骚年。不然你再等等。

结语

通过这一下午的尝试,追踪源码,我发现自己确实挺乐在其中的。然而,这花费了大量的时间和精力。所以,我花费了更多的时间一定要把这次经历记录下来,也就是本文了。想说的是,最新的版本果然是坑巨多,慎入!!!如果是作为生产环境的选型,必须跳过这样的版本。当然,如果是自己个人研究,看新的没错。

那么,我到底应不应该学习2.0呢,毕竟1.5也没学完呢。

学吧,按2.0的学习,工作中还是用1.5. 嗯,就这样吧。

Miao语

没有解决不了的bug,只要你用心研究,都可以解决。

参考