SpringCloud核心组件(二)

1.Eureka 高可用

在 eureka 的基础上添加 Spring security(增加安全性,如密码验证操作)

a.在 eureka 模块中引入 spring-boot-starter-security 依赖

1
2
3
4
5
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

b.修改注册中心配置文件 application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server:
port: 8083

eureka:
instance:
hostname: localhost # 当前服务所在服务器的域名
client:
register-with-eureka: false # 不向注册中心注册自己
fetch-registry: false # 不检索服务
service-url: # 注册中心的地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
security:
basic:
enabled: true
user:
name: username
password: password123

c.添加配置类 SecurityConfig

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
package com.nianxi.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

/**
* @author Jie.
* @description: TODO
* @date 2024/11/12
* @version: 1.0
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private AuthenticationConfiguration authenticationConfiguration;

@Bean
public AuthenticationManager authenticationManager() throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable);
return http.build();
}
}

20241112162129

d.修改 provide 模块的配置文件

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: service-provide
server:
port: 8081

eureka:
client:
proxy-password: password123
proxy-user-name: username
service-url:
defaultZone: http://localhost:8083/eureka/

consumer 模块同理

20241112163954

注意:

  • 当 provide 跟 consumer 已经建立连接之后停掉注册中心,不会影响服务的可用性(AP)

  • 如果 consumer 没有与 provide 建立连接,即在停掉注册中心之前没有访问过,那么服务会不可用

将 Eureka 搭建为高可用集群

a.创建 eureka-02 模块

修改其配置文件,打开 client 的其中注册自己服务与检索服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:
port: 8084

eureka:
instance:
hostname: localhost # 当前服务所在服务器的域名
client:
register-with-eureka: true # 向注册中心注册自己
fetch-registry: true # 检索服务
service-url: # 注册中心的地址
defaultZone: http://${eureka.instance.hostname}:8083/eureka/
proxy-user-name: username
proxy-password: password123

spring:
security:
basic:
enabled: true
user:
name: username
password: password123

b.建立 eureka-01 与 eureka-02 的通信,即把地址换成对方的

01.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:
port: 8083

eureka:
instance:
hostname: localhost # 当前服务所在服务器的域名
client:
register-with-eureka: true # 向注册中心注册自己
fetch-registry: true # 检索服务
service-url: # 注册中心的地址
defaultZone: http://${eureka.instance.hostname}:8084/eureka/
proxy-user-name: username
proxy-password: password123

spring:
security:
basic:
enabled: true
user:
name: username
password: password123

02.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:
port: 8084

eureka:
instance:
hostname: localhost # 当前服务所在服务器的域名
client:
register-with-eureka: true # 向注册中心注册自己
fetch-registry: true # 检索服务
service-url: # 注册中心的地址
defaultZone: http://${eureka.instance.hostname}:8083/eureka/
proxy-user-name: username
proxy-password: password123

spring:
security:
basic:
enabled: true
user:
name: username
password: password123

注意:由于 eureka 设置了密码,要添加密码到 client 下

d.在 provide 跟 consumer 模块中注册多个 eureka 即可

provide

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: service-provide
server:
port: 8081

eureka:
client:
proxy-password: password123
proxy-user-name: username
service-url:
defaultZone: http://localhost:8083/eureka/,http://localhost:8084/eureka/

consumer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
spring:
application:
name: service-consumer
server:
port: 8082

eureka:
client:
proxy-password: password123
proxy-user-name: username
service-url:
defaultZone: http://localhost:8083/eureka/,http://localhost:8084/eureka/

user:
userServicePath: http://SERVICE-PROVIDE/simple/

关闭其中一个 eureka 之后测试
http://localhost:8082/user/2
可以访问,说明 eureka 的高可用就搭建完成了

2.Ribbon 负载均衡

在 SpringCloud 中自带负载均衡策略

在 consumer 模块中加入 Ribbon 组件

1
2
3
4
5
6
<!-- ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>

启动一个 Eureka 服务,修改 provide 的端口为 8085,修改 UserController

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: service-provide
server:
port: 8085

eureka:
client:
proxy-password: password123
proxy-user-name: username
service-url:
defaultZone: http://localhost:8083/eureka/,http://localhost:8084/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
package com.nianxi.provider.controller;

import com.nianxi.provider.pojo.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
* @author Jie.
* @description: TODO
* @date 2024/11/12
* @version: 1.0
*/
@RestController
public class UserController {

@GetMapping("/simple/{id}")
public User findById(@PathVariable("id") Long id) {
return User.builder()
.id(id)
.username("star hello" + id)
.build();
}
}

在调用http://localhost:8082/user/5时 eureka 会调用另外一个 eureka 服务,验证其负载均衡
20241112173512

3.Feign

Feign 是一个声明式的 Web Service 客户端。它让微服务之间的调用变得更简单。Feign 具有可插拔式的注解支持,包括 Feign 注解和 JAX-RS 注解。Feign 还支持可插拔的编码器和解码器。Spring Cloud 增加了对 Spring MVC 注解的支持,并且也支持 Spring WebFlux。

Feign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡。

a.创建 Feign 模块,并引入依赖

pom.xml

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
<?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>
<parent>
<groupId>com.nianxi</groupId>
<artifactId>springcloud_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>

<artifactId>Feign</artifactId>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>

</project>

b.创建 FeignApplication 启动类,添加@EnableFeignClients 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.nian.feign;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
* @author Jie.
* @description: TODO
* @date 2024/11/12
* @version: 1.0
*/
@SpringBootApplication
@EnableFeignClients
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
}

c.配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8083/eureka/
proxy-user-name: username
proxy-password: password123

server:
port: 8086

spring:
application:
name: service-feign

d.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.nian.feign.service;

import com.nian.feign.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
* @author Jie.
* @description: TODO
* @date 2024/11/12
* @version: 1.0
*/
@FeignClient(value = "SERVICE-PROVIDER")
public interface UserService {

// @RequestMapping(value = "simple/{id}",method = RequestMethod.GET)
@GetMapping("/simple/{id}")
User getUserById(@PathVariable("id") Long id);
}

e.user

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package com.nian.feign.pojo;

import lombok.*;

/**
* @author Jie.
* @description: TODO
* @date 2024/11/12
* @version: 1.0
*/
@Data
@AllArgsConstructor
@ToString
@NoArgsConstructor
@Builder
public class User {
private Long id;
private String username;
}

f.UserController

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
package com.nian.feign.controller;

import com.nian.feign.pojo.User;
import com.nian.feign.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
* @author Jie.
* @description: TODO
* @date 2024/11/12
* @version: 1.0
*/
@RestController
public class UserController {

@Autowired
private UserService userService;

@GetMapping("/test")
public User sayHi(@RequestParam Long id){
return userService.getUserById(id);
}
}