0%

SpringCloud学习笔记

SpringCloud

服务发现Euraka

1、创建空父maven项目,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
<?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>
<!-- <modules>
<module>euraka-server</module>
<module>user-web</module>
<module>user-provide01</module>
<module>euraka-server02</module>
<module>user-provide02</module>
<module>user-web02</module>
<module>user-web03</module>
</modules> -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<groupId>com.syl</groupId>
<artifactId>springcloud01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、创建springboot项目,选择spring Cloud Discovery –> Eureka 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
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.syl</groupId>
<artifactId>springcloud01</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.syl</groupId>
<artifactId>euraka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>euraka-server</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RC1</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

</project>

3、application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#内置的tomcat服务启动监听端口号
server:
port: 8888
#应用名称
spring:
application:
name: eureka-server01
#EurekaServer配置
eureka:
client:
register-with-eureka: false #此EurekaServer不在注册到其他的注册中心
fetch-registry: false #不在从其他中心中心拉取服务器信息
service-url:
defaultZone: http://localhost:${server.port}/eureka #注册中心访问地址
4、启动类
1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableEurekaServer
public class AppStart {

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

浏览器地址栏输入 http://localhost:8888/测试

5、服务提供方,以往的service层和dao层,使用jpa

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
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.syl</groupId>
<artifactId>springcloud01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.syl</groupId>
<artifactId>user-provide01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-provide01</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RC1</spring-cloud.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-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

</project>

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server:
port: 10010

spring:
application:
name: userprovider
datasource:
url: jdbc:mysql://localhost:3306/tempdata?serverTimezone=UTC
username: root
password: root001
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true

User.java

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
package com.syl.userprovide01.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:21
* @Description:
*/
@Entity

@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
public class User {
@Id
@GeneratedValue
private Integer id;

@Column(name="name",nullable = true,length = 20)
private String name;

@Column(name = "age",nullable = true,length = 4)
private Integer age;


public User() {
}

public User(String name, Integer age) {
this.name = name;
this.age = age;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

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

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

UserController.java

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
package com.syl.userprovide01.controller;

import com.syl.userprovide01.entity.User;
import com.syl.userprovide01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:39
* @Description:
*/
@RestController
@RequestMapping("/user")
public class UserController {


@Autowired
UserService userService;

@GetMapping("/getall")
public Map<String,Object> getUsers() {
Map<String,Object> map=new HashMap<>();
List<User> list = userService.getUserList();
map.put("list", list);
String ProviderVersion="User-Provide01";
map.put("ProviderVersion", ProviderVersion);
return map;
}

@PostMapping("/save")
public String createUser(@RequestBody User user) {
try {
userService.createUser(user);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "error";
}
return "success";
}
@GetMapping("/get/{id}")
public User findUser(@PathVariable("id") Integer id) {
User user =null;
try {
user= userService.getUser(id);
System.out.println("返回user:"+user);
} catch (Exception e) {

//e.printStackTrace();
System.out.println("数据查询失败:");
return user;
}
return user;
}

@PutMapping("/update/{id}")
public String editUser(@RequestBody User user, @PathVariable("id") Integer id) {
try {
userService.updateUser(user.getId(), user);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
return "success";
}

@DeleteMapping("/delete/{id}")
public String deleteUser(@PathVariable("id") Integer id) {
try {
userService.deleteUser(id);
} catch (Exception e) {
e.printStackTrace();
return "error";
}
return "success";

}

@GetMapping("/getversion")
public String getVersion() {

return "User-Provide01";
}
}

UserService

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.syl.userprovide01.service;

import com.syl.userprovide01.entity.User;

import java.util.List;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:24
* @Description:
*/
public interface UserService {
//获取全部用户数据
public List<User> getUserList();
//新增用户数据
public void createUser(User user);
//获取指定id用户信息
public User getUser(Integer id);
//更新指定id用户信息
public void updateUser(Integer id,User user);
//删除指定id用户
public void deleteUser(Integer id);

}

UserServiceImpl.java

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
package com.syl.userprovide01.service.impl;

import com.syl.userprovide01.dao.UserRepository;
import com.syl.userprovide01.entity.User;
import com.syl.userprovide01.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:25
* @Description:
*/
@Service
public class UserServiceImpl implements UserService {

@Autowired
UserRepository userRepository;

@Override
public List<User> getUserList() {
return userRepository.findAll();
}

@Override
public void createUser(User user) {
userRepository.save(user);
}

@Override
public User getUser(Integer id) {
return userRepository.getOne(id);
}

@Override
public void updateUser(Integer id, User user) {
user.setId(id);
userRepository.saveAndFlush(user);
}

@Override
public void deleteUser(Integer id) {
userRepository.deleteById(id);
}
}

UserRepository.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.syl.userprovide01.dao;

import com.syl.userprovide01.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:22
* @Description:
*/
public interface UserRepository extends JpaRepository<User,Integer> {
}

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.syl.userprovide01;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableDiscoveryClient
public class UserProvide01Application {

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

}
6、消费方,以往的controller层

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
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
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.syl</groupId>
<artifactId>springcloud01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.syl</groupId>
<artifactId>user-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-web</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RC1</spring-cloud.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-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.2.1</version>
</dependency>


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

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

</project>

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 10086
spring:
thymeleaf:
cache: false

application:
name: userweb1
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
instance:
prefer-ip-address: true

UserController.java

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
package com.syl.userweb.controller;

import com.syl.userweb.entity.User;
import com.syl.userweb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;
import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-06 20:06
* @Description:
*/
@Controller
public class UserController {

@Autowired
UserService userService;

@GetMapping("/")
public String getUserList(Model model){
Map map = userService.getUserMap();
List<User> list=(List<User>) map.get("list");
model.addAttribute("page", list);
model.addAttribute("ProviderVersion", map.get("ProviderVersion"));

return "user/list";
}

@RequestMapping("/toAdd")
public String toadd(User user){
return "user/userAdd";//跳转到userAdd.html
}
@PostMapping("/add")
public String createUser(User user) {
userService.createUser(user);
return "redirect:/";
}
@RequestMapping("/toEdit/{id}")
public String toEdit(Model model,@PathVariable("id")Integer id){
User user = userService.getUser(id);
model.addAttribute("user",user);
return "user/userEdit"; //跳转到userEdit.html页面
}

@RequestMapping("/edit")
public String edit(User user){
userService.updateUser(user.getId(), user);
return "redirect:/";//获取列表数据并显示
}
@GetMapping("/delete/{id}")
public String deleteUser(@PathVariable("id") Integer id) {
userService.deleteUser(id);
return "redirect:/";

}


}

User.java

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
package com.syl.userweb.entity;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:53
* @Description:
*/

public class User {

private Integer id;

private String name;

private Integer age;

public User() {
}

public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getName() {
return name;
}

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

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

UserService.java

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

import com.syl.userweb.entity.User;

import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:54
* @Description:
*/
public interface UserService {
public Map getUserMap();
public void createUser(User user);
public User getUser(Integer id);
public void updateUser(Integer id,User user);
public void deleteUser(Integer id);

}

UserServiceImpl.java

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
package com.syl.userweb.service.impl;

import com.netflix.appinfo.InstanceInfo;


import com.syl.userweb.entity.User;
import com.syl.userweb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;


import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:54
* @Description:
*/
@Service
public class UserServiceImpl implements UserService {
//远程服务调用客户端
@Autowired
RestTemplate restTemplate;


@Autowired
DiscoveryClient discoveryClient;

public String getServerUrl() {

List<ServiceInstance> userprovide = discoveryClient.getInstances("USERPROVIDER");
System.out.println(userprovide);
//获取第一个服务器
ServiceInstance inst = userprovide.get(0);

String instanceId = inst.getInstanceId();

System.out.println(instanceId);

//获取服务提供者服务器ip、端口号
String ip = inst.getHost();
int port = inst.getPort();
//拼接调用地址
String url="http://"+ip+":"+port+"/user";
System.out.println(url);
return url;

}

@Override
public Map getUserMap() {
Map map = restTemplate.getForObject(getServerUrl()+"/getall", Map.class);
System.out.println("come here");

return map;
}

@Override
public void createUser(User user) {
restTemplate.postForObject(getServerUrl() + "/save", user, String.class);
}

@Override
public User getUser(Integer id) {
return restTemplate.getForObject(getServerUrl() + "/get/" + id, User.class);
}

@Override
public void updateUser(Integer id, User user) {
restTemplate.put(getServerUrl() + "/update/" + id, user);
}

@Override
public void deleteUser(Integer id) {
restTemplate.delete(getServerUrl() + "/delete/" + id);
}
}

resources/templates/user/myfragment.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" >
<title>Title</title>
</head>
<body>
<h1 th:fragment="head1" align="center">用户管理系统</h1>
<h1 th:fragment="foot1">
&copy; 1999-2018 Offcn.All Rights Reserved
</h1>

</body>
</html>

resources/templates/user/list.html

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
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>userList</title>
<link rel='stylesheet' th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.min.css}" href='webjars/bootstrap/4.2.1/css/bootstrap.min.css'>
</head>
<body class="container">
<div th:insert="~{user/myfragment :: head1}"></div>
<br/>
<h1><em th:text="${ProviderVersion}">服务提供方信息</em></h1>
<br/><br/>
<div class="with:80%">
<div class="form-group">
<div class="col-sm-2 control-label">
<a href="toAdd" th:href="@{toAdd}" class="btn btn-info">add</a>
</div>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Age</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${page}">
<th scope="row" th:text="${user.id}">1</th>
<td th:text="${user.name}">neo</td>
<td th:text="${user.age}">6</td>
<td><a th:href="@{'toEdit/'+${user.id}}">edit</a></td>
<td><a th:href="@{'delete/'+${user.id}}">delete</a></td>
</tr>
</tbody>

</table>

</div>
<div th:include="~{user/myfragment :: foot1}"></div>
</body>
</html>

resources/templates/user/userAdd.html

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
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>user</title>
<link rel='stylesheet' th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.min.css}" href='webjars/bootstrap/4.2.1/css/bootstrap.min.css'>
</head>
<body class="container">
<div th:insert="~{user/myfragment :: head1}"></div>
<br/>
<h1>添加用户</h1>
<br/><br/>
<div class="with:80%">
<form class="form-horizontal" th:action="@{add}" method="post">
<div class="form-group">
<label for="name" class="col-sm-2 control-label">name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" id="name" placeholder="name"/>
</div>
</div>

<div class="form-group">
<label for="age" class="col-sm-2 control-label">age</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="age" id="age" placeholder="age"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Submit" class="btn btn-info" />
&nbsp; &nbsp; &nbsp;
<input type="reset" value="Reset" class="btn btn-info" />
</div>

</div>
</form>
</div>
<div th:include="~{user/myfragment :: foot1}"></div>
</body>
</html>

resources/templates/user/userEdit.html

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
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>user</title>
<link rel='stylesheet' th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.min.css}" href='webjars/bootstrap/4.2.1/css/bootstrap.min.css'>
</head>
<body class="container">
<div th:insert="~{user/myfragment :: head1}"></div>
<br/>
<h1>修改用户</h1>
<br/><br/>
<div class="with:80%">
<form class="form-horizontal" th:action="@{/edit}" th:object="${user}" method="post">
<input type="hidden" name="id" th:value="*{id}" />
<div class="form-group">
<label for="name" class="col-sm-2 control-label">name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" id="name" th:value="*{name}" placeholder="name"/>
</div>
</div>

<div class="form-group">
<label for="age" class="col-sm-2 control-label">age</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="age" id="age" th:value="*{age}" placeholder="age"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Submit" class="btn btn-info" />
&nbsp; &nbsp; &nbsp;
<a href="/" th:href="@{/}" class="btn btn-info">Back</a>
</div>

</div>
</form>
</div>
<div th:include="~{user/myfragment :: foot1}"></div>
</body>
</html>

启动类

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.syl.userweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class UserWebApplication {

public static void main(String[] args) {
SpringApplication.run(UserWebApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

7、注意事项

报错说serviceimpl中的restTemplate无法装载

在启动类中加入:

1
2
3
4
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}

从消费方访问提供方时获取host时获取的是主机名不是ip的解决

application.yml中添加prefer-ip-address:true,优先使用ip注册服务

1
2
3
4
5
6
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
instance:
prefer-ip-address: true

Eureka高可用

1、复制EurakaServer01改名为02并修改配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#内置的tomcat服务启动监听端口号
server:
port: 8889
#应用名称
spring:
application:
name: eureka-server01
#EurekaServer配置
eureka:
client:
register-with-eureka: false #此EurekaServer不在注册到其他的注册中心
fetch-registry: false #不在从其他中心中心拉取服务器信息
service-url:
defaultZone: http://localhost:8888/eureka #另一个服务注册中心访问地址
2、修改EurakaServer01的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#内置的tomcat服务启动监听端口号
server:
port: 8888
#应用名称
spring:
application:
name: eureka-server01
#EurekaServer配置
eureka:
client:
register-with-eureka: false #此EurekaServer不在注册到其他的注册中心
fetch-registry: false #不在从其他中心中心拉取服务器信息
service-url:
defaultZone: http://localhost:8889/eureka #另一个服务注册中心访问地址
3、修改提供方的配置文件为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server:
port: 10010

spring:
application:
name: userprovider
datasource:
url: jdbc:mysql://localhost:3306/tempdata?serverTimezone=UTC
username: root
password: root001
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
#一定注意eureka与spring属于平级 注意格式
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/ #两个服务中心都注册,用,隔开
instance:
prefer-ip-address: true
4、修改消费方配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 10086
spring:
thymeleaf:
cache: false

application:
name: userweb1
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
instance:
prefer-ip-address: true

服务调用组件

1、 服务调用基于LoadBalancerClient
  • 创建第二个服务提供方,配置文件主要更改
1
2
3
4
5
server:
port: 8002 #端口号不相同
spring:
application:
name: userprovider # 服务名相同
  • 创建第二个消费方,配置文件主要更改
1
2
3
4
5
6
7
server:
port: 10087 #端口号不相同
spring:
thymeleaf:
cache: false
application:
name: userweb2 # 不同
  • 修改消费方的UserServiceImpl.java中的getUrl()方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class UserServiceImpl implements UserService {

//远程服务调用客户端
@Autowired
RestTemplate restTemplate;
//支持负载均衡的调用客户端
@Autowired
LoadBalancerClient loadBalancerClient;

/***
* 通过客户端负载均衡器获取生产者服务器基础地址
* @return
*/
public String getServerUrl() {
//通过客户端调用服务均衡器查找服务
ServiceInstance inst = loadBalancerClient.choose("USERPROVIDER");
//获取服务提供者服务器ip、端口号
String ip = inst.getHost();
int port = inst.getPort();
//拼接调用地址
String url="http://"+ip+":"+port+"/user";
return url;
}
}
2、服务调用基于Ribbon
  • 创建新消费方模块03,引入依赖
1
2
3
4
5
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

  • 修改配置文件
1
2
3
4
5
6
7
8
9
10
server:
port: 10088
spring:
thymeleaf:
cache: false
main:
#当遇到同样名字的时候,是否允许覆盖注册
allow-bean-definition-overriding: true
application:
name: userweb
  • 修改启动类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.syl.userweb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class UserWeb03Application {

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(UserWeb03Application.class, args);
}
}
  • 修改UserServiceImpl实现类
1
2
3
4
5
//远程服务调用客户端
@Autowired
RestTemplate restTemplate;
//开启Ribbon后,RestTemplate直接使用服务名就可以发起调用
String url="http://USERPROVIDER";
  • 负载均衡配置

# com.netflix.loadbalancer.RandomRule #配置规则 随机

# com.netflix.loadbalancer.RoundRobinRule #配置规则 轮询

# com.netflix.loadbalancer.RetryRule #配置规则 重试

# com.netflix.loadbalancer.WeightedResponseTimeRule #配置规则 响应时间权重

# com.netflix.loadbalancer.BestAvailableRule #配置规则 最空闲连接策略

1
2
3
USERPROVIDER: #服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
  • 重试机制配置

引入依赖

1
2
3
4
5
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
spring:
#开启Spring Cloud的重试功能
cloud:
loadbalancer:
retry:
enabled: true
USERPROVIDER:
ribbon:
#配置指定服务的负载均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# Ribbon的连接超时时间
ConnectTimeout: 250
# Ribbon的数据读取超时时间
ReadTimeout: 250
# 是否对所有操作都进行重试
OkToRetryOnAllOperations: true
# 切换实例的重试次数
MaxAutoRetriesNextServer: 1
# 对当前实例的重试次数
MaxAutoRetries: 1
3、服务调用基于Feign
  • 依赖
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • 配置文件端口号更改
1
2
server:
port: 10089
  • 修改应用启动类,增加注解@EnableFeignClients
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.syl.userweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class UserWeb04Application {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(UserWeb04Application.class, args);
}
}
  • 修改接口UserService.java,删除实现类UserServiceImpl
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
package com.syl.userweb.service;

import com.syl.userweb.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:54
* @Description:
*/
@FeignClient("USERPROVIDER")
public interface UserService {
@GetMapping("/user/getall")
public Map getUserMap();
@PostMapping("/user/save")
public void createUser(User user);
@GetMapping("/user/get/{id}")
public User getUser( @RequestParam("id") Integer id);
@PutMapping("/user/update/{id}")
public void updateUser(@RequestParam("id") Integer id, User user);
@DeleteMapping("/user/delete/{id}")
public void deleteUser( @RequestParam("id") Integer id);
}

熔断器组件Netflix Hystrix

1、Ribbon使用Hystix

基于消费方03模块修改

  • pom
1
2
3
4
5
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

  • 修改应用启动类。增加注解@EnableCircuitBreaker
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
package com.syl.userweb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class UserWeb03Application {

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(UserWeb03Application.class, args);
}
}
  • 修改业务实现类UserServiceImpl
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
package com.syl.userweb.service.impl;

import com.netflix.appinfo.InstanceInfo;


import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.syl.userweb.entity.User;
import com.syl.userweb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-06 19:54
* @Description:
*/
@Service
public class UserServiceImpl implements UserService {
//远程服务调用客户端
@Autowired
RestTemplate restTemplate;


String url = "http://USERPROVIDER/user";


//熔断回调函数
public Map<String, Object> getUserMapFallbackMethod() {
System.out.println("调用失败!");
Map map = new HashMap();
map.put("list", new ArrayList<>());
map.put("ProviderVersion", "获取远程调用失败");
return map;

}
@Override
@HystrixCommand(fallbackMethod = "getUserMapFallbackMethod") //注解添加到需要熔断的连接方法上
public Map getUserMap () {
long beginTime = System.currentTimeMillis();
Map map = restTemplate.getForObject(url + "/getall", Map.class);
long endTime = System.currentTimeMillis();
System.out.println("程序执行时间:" + (endTime - beginTime));

return map;
}

@Override
public void createUser (User user){
restTemplate.postForObject(url + "r/save", user, String.class);
}

@Override
public User getUser (Integer id){
return restTemplate.getForObject(url + "/get/" + id, User.class);
}

@Override
public void updateUser (Integer id, User user){
restTemplate.put(url + "/update/" + id, user);
}

@Override
public void deleteUser (Integer id){
restTemplate.delete(url + "/delete/" + id);
}
}

默认超时时间为1000ms,可以在配置文件中配置,为了项目的正常运行,熔断时间一定大于超时时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
USERPROVIDER:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# Ribbon的连接超时时间
ConnectTimeout: 250
# Ribbon的数据读取超时时间
ReadTimeout: 250
# 是否对所有操作都进行重试
OkToRetryOnAllOperations: true
# 切换实例的重试次数
MaxAutoRetriesNextServer: 1
# 对当前实例的重试次数
MaxAutoRetries: 1
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
2、Feign使用Hystix
  • 修改消费方04的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
# 开启Feign的熔断功能
feign:
hystrix:
enabled: true
#设定Hystrix熔断超时时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000
  • 编写Feign声明接口UserService的实现类UserServiceImpl(注意要声明为@Service)
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
package com.syl.userweb.service.impl;

import com.syl.userweb.entity.User;
import com.syl.userweb.service.UserService;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
* @Auther: Administrator
* @Date: 2019-11-07 18:49
* @Description:
*/
@Service
public class UserServiceImpl implements UserService {
@Override
public Map getUserMap() {
System.out.println("请求失败");
Map map = new HashMap();
map.put("list", new ArrayList<>());
map.put("ProviderVersion", "获取远程调用失败");
return map;

}

@Override
public void createUser(User user) {
System.out.println("创建用户失败:"+user);
}

@Override
public User getUser(Integer id) {
System.out.println("获取id:"+id+" 的用户失败");
return null;

}

@Override
public void updateUser(Integer id, User user) {
System.out.println("更新id:"+id+"的用户失败");
}

@Override
public void deleteUser(Integer id) {
System.out.println("删除id为:"+id+"的用户失败");
}
}
  • 创建Feign配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.syl.userweb.util;

import feign.Contract;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @Auther: Administrator
* @Date: 2019-11-07 19:01
* @Description:
*/
@Configuration
public class FeignConfiguration {

@Bean
public Logger.Level getFeignlogger(){
return Logger.Level.FULL;
}
}
  • 在Feign调用接口UserService中,使用注解@FeignClient声明熔断调用实现类
1
@FeignClient(value="USERPROVIDER",configuration= FeignConfiguration.class,fallback= UserServiceImpl.class)
  • 手动设置服务方方法睡眠时间模拟超时

重启项目验证

3、 Hystix监控服务器搭建
  • 新建一个springBoot模块hystrix-dashboard ,添加依赖
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
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.syl</groupId>
<artifactId>springcloud01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.syl</groupId>
<artifactId>hystrix-dashboard</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hystrix-dashboard</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RC1</spring-cloud.version>
<spring-boot.version>2.2.0.RELEASE</spring-boot.version>
<hystrix.version>2.2.0.RC1</hystrix.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>${hystrix.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>${hystrix.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

</project>

  • ​ 为应用主类加上@EnableHystrixDashboard,启用Hystrix Dashboard功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.syl.hystrixdashboard;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {

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

}
  • 配置文件
1
2
3
4
5
spring:
application:
name: hystrix-dashboard
server:
port: 1301

浏览器访问http://localhost:1301/hystrix测试

4、启用客户端Hystix监控
  • 修改项目消费方04的pom.xml增加Hystrix监控所需依赖包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<properties>
<hystrix.version>2.2.0.RC1</hystrix.version>
</properties>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>${hystrix.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

  • 启动类中添加注解,以及数据监控地址
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
package com.syl.userweb;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix //开启监控
public class UserWeb04Application {

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {

SpringApplication.run(UserWeb04Application.class, args);
}

//配置访问地址
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1); //系统启动时加载顺序
registrationBean.addUrlMappings("/hystrix.stream");//路径
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
  • 访问测试

首先 http://localhost:10089/ 访问正常项目

其次 http://localhost:9004/hystrix.stream 查看数据监控

输入 http://localhost:1301/hystrix访问Hystrix Dashboard的首页

在Hystrix Dashboard的首页输入 http://localhost:9004/hystrix.stream 点击Monitor Stream查看图形化监控

分布式配置中心组件Spring Cloud Config

1、构建Config Server
  • 新建模块ConfigServer001,修改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
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
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.syl</groupId>
<artifactId>springcloud01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.syl</groupId>
<artifactId>config-server01</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>config-server01</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.RC1</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>

</project>

  • 修改启动程序,并添加@EnableConfigServer注解,开启Config Server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.syl.configserver01;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServer01Application {

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

}
  • 修改配置文件application.yml配置服务信息以及git信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 7001

spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/WINNER003/SpringBootServerConfig #https://github.com/用户名/仓库名
search-paths: src/main/resources #所在文件夹
username: WINNER003 #用户名
password: *** #密码

URL与配置文件的映射关系如下:

/{application}/{profile}[/{label}]

/{application}-{profile}.yml

/{label}/{application}-{profile}.yml

/{application}-{profile}.properties

/{label}/{application}-{profile}.properties

上面的url会映射{application}-{profile}.properties对应的配置文件,{label}对应git上不同的分支,默认为master。

2、Config Client客户端调用配置中心配置,并实现动态刷新——有待进一步测试
  • 修改项目提供方01的pom.xml引入依赖包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</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-actuator</artifactId>
</dependency>

  • 将原来的配置文件清空,在同级目录下创建bootstrap.yml文件
1
2
3
4
5
6
7
8
spring:
application:
name: UserProvdier01 # 必须和本项目名一致
cloud:
config:
uri: http://localhost:7001 #configserver的地址
profile: test #按配置文件属性填写
label: master #按配置文件属性填写
  • 在application.yml文件里开启自动刷新
1
2
3
4
5
management:
endpoints:
web:
exposure:
include: refresh,health,info
  • 在UserController控制器上添加注解@RefreshScope
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
@RestController
@RequestMapping("/user")
@RefreshScope //加上这个
public class UserController {


@Autowired
UserService userService;

@Value("${ProviderVersion}")
private String providerVersion; //在github上的配置文件里添加键值对ProviderVersion来验证


@GetMapping("/getall")
public Map<String,Object> getUsers() {
try {
System.out.println("睡眠");
//让主线程随机睡眠0--1200毫秒,模拟发生熔断
int i = new Random().nextInt(6000);
System.out.println(i+"ms");
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}

Map<String,Object> map=new HashMap<>();
List<User> list = userService.getUserList();
map.put("list", list);
// String ProviderVersion="User-Provide01";
map.put("ProviderVersion", providerVersion);
return map;
}

3、高可用ConfigServer
  • config-server01引入依赖
1
2
3
4
5
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

  • yml文件配置注册中心
1
2
3
4
5
6
# 配置服务注册中心
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka,http://localhost:8889/eureka

  • 启动类添加@EnableDiscoveryClient
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServer001Application {

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

  • 复制config-server01创建模块config-server002,更改端口号 其他不变
1
2
server:
port: 7002
  • 配置客户端使用高可用配置中心,确保客户端项目UserProvdier01的pom.xml的有使用Eureka的客户端包
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 修改bootstrap.yml文件 注意cloud一定要在eureka配置项之前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
application:
name: UserProvdier01
cloud:
config:
discovery:
enabled: true
service-id: config-server
profile: test
label: master
eureka:
client:
service-url:
defaultZone: http://localhost:8888/eureka,http://localhost:8889/eureka
  • 修改项目启动类,增加@EnableDiscoveryClient注解

重启项目,测试

服务网关组件Netflix Zuul

赏口饭吃吧!