主要讲解SpringCloud搭建微服务的步骤,其中用到了Eurake、Ribbon、Feign、Hystrix、Zuul、Config技术。
项目地址:https://github.com/17665387407?tab=repositories
一、建立一个总工程
首先建立一个microservice-parent总工程,总工程中并不做什么业务逻辑,总工程主要定义一个POM文件,将后续各个微服公用的一些jar包在总工程的pom中进行导入。为方便起见,建立一个working set用于归类所有的微服务,命名为springcloudset。然后建立总工程
New -> Maven -> Maven Project
注意,Packaging模式要选择pom模式,不要选择jar模式。
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 1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>com.hjp.springcloud</groupId>
6 <artifactId>microservice-parent</artifactId>
7 <version>0.0.1-SNAPSHOT</version>
8 <packaging>pom</packaging>
9
10 <properties>
11 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12 <maven.compiler.source>1.8</maven.compiler.source>
13 <maven.compiler.target>1.8</maven.compiler.target>
14 <junit.version>4.12</junit.version>
15 <log4j.version>1.2.17</log4j.version>
16 <lombok.version>1.16.18</lombok.version>
17 </properties>
18
19 <dependencyManagement>
20 <dependencies>
21 <dependency>
22 <groupId>org.springframework.cloud</groupId>
23 <artifactId>spring-cloud-dependencies</artifactId>
24 <version>Dalston.SR1</version>
25 <type>pom</type>
26 <scope>import</scope>
27 </dependency>
28 <dependency>
29 <groupId>org.springframework.boot</groupId>
30 <artifactId>spring-boot-dependencies</artifactId>
31 <version>1.5.9.RELEASE</version>
32 <type>pom</type>
33 <scope>import</scope>
34 </dependency>
35 <dependency>
36 <groupId>mysql</groupId>
37 <artifactId>mysql-connector-java</artifactId>
38 <version>5.1.46</version>
39 </dependency>
40 <dependency>
41 <groupId>com.alibaba</groupId>
42 <artifactId>druid</artifactId>
43 <version>1.1.0</version>
44 </dependency>
45 <dependency>
46 <groupId>org.mybatis.spring.boot</groupId>
47 <artifactId>mybatis-spring-boot-starter</artifactId>
48 <version>1.3.0</version>
49 </dependency>
50 <dependency>
51 <groupId>ch.qos.logback</groupId>
52 <artifactId>logback-core</artifactId>
53 <version>1.2.3</version>
54 </dependency>
55 <dependency>
56 <groupId>junit</groupId>
57 <artifactId>junit</artifactId>
58 <version>${junit.version}</version>
59 <scope>test</scope>
60 </dependency>
61 <dependency>
62 <groupId>log4j</groupId>
63 <artifactId>log4j</artifactId>
64 <version>${log4j.version}</version>
65 </dependency>
66 </dependencies>
67 </dependencyManagement>
68</project>
69
二、建立公共微服
然后建立一个microservice-com的公共模块,用于提供后续微服需要的公共的东西。创建好公共模块,其它微服务需要的话,不用再创建,直接引用该模块即可。
1、下面在总工程下,即microservice-parent下创建第一个微服务microservice-com模块。
New -> Maven -> Maven Module
注意,Packaging不要选择pom模式,而应该选择ja模式,后续的微服都是如此。
pom.xml内容为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <!-- 继承父工程 -->
4 <parent>
5 <groupId>com.hjp.springcloud</groupId>
6 <artifactId>microservice-parent</artifactId>
7 <version>0.0.1-SNAPSHOT</version>
8 </parent>
9 <!-- 当前工程的名字 -->
10 <artifactId>microservice-com</artifactId>
11 <dependencies><!-- 当前Module需要用到的jar包,按自己需求添加,如果父类已经包含了,可以不用写版本号 -->
12 <dependency>
13 <groupId>org.projectlombok</groupId>
14 <artifactId>lombok</artifactId>
15 </dependency>
16 </dependencies>
17</project>
18
2、然后在该模块中建立一个User的bean,以供其它微服务进行调用。
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 1package com.hjp.entity;
2public class User {
3 private int id;
4 private String name;
5 private int age;
6
7 public User() {
8 super();
9 }
10
11 public User(int id, String name, int age) {
12 super();
13 this.id = id;
14 this.name = name;
15 this.age = age;
16 }
17
18 public int getId() {
19 return id;
20 }
21
22 public void setId(int id) {
23 this.id = id;
24 }
25
26 public String getName() {
27 return name;
28 }
29
30 public void setName(String name) {
31 this.name = name;
32 }
33
34 public int getAge() {
35 return age;
36 }
37
38 public void setAge(int age) {
39 this.age = age;
40 }
41
42 @Override
43 public String toString() {
44 return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
45 }
46
47}
48
3、创建完公共微服后,执行mvn clean install进行装载。
创建完microservice-com模块后,在microservice-parent父工程中的pom.xml文件中增加了
1
2
3
4 1<modules>
2 <module>microservice-com</module>
3 </modules>
4
三、建立microservice-provider微服务
1、与建立microservice-com服务类似,建立一个microservice-provider微服务
2、该服务用于提供直接操作数据库user表。首先在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 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <parent>
4 <groupId>com.hjp.springcloud</groupId>
5 <artifactId>microservice-parent</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 </parent>
8
9 <artifactId>microservice-provider</artifactId>
10
11 <dependencies>
12 <dependency>
13 <groupId>com.hjp.springcloud</groupId>
14 <artifactId>microservice-com</artifactId>
15 <version>${project.version}</version>
16 </dependency>
17 <dependency>
18 <groupId>junit</groupId>
19 <artifactId>junit</artifactId>
20 </dependency>
21 <dependency>
22 <groupId>mysql</groupId>
23 <artifactId>mysql-connector-java</artifactId>
24 </dependency>
25 <dependency>
26 <groupId>com.alibaba</groupId>
27 <artifactId>druid</artifactId>
28 </dependency>
29 <dependency>
30 <groupId>ch.qos.logback</groupId>
31 <artifactId>logback-core</artifactId>
32 </dependency>
33 <dependency>
34 <groupId>org.mybatis.spring.boot</groupId>
35 <artifactId>mybatis-spring-boot-starter</artifactId>
36 </dependency>
37 <dependency>
38 <groupId>org.springframework.boot</groupId>
39 <artifactId>spring-boot-starter-jetty</artifactId>
40 </dependency>
41 <dependency>
42 <groupId>org.springframework.boot</groupId>
43 <artifactId>spring-boot-starter-web</artifactId>
44 </dependency>
45 <dependency>
46 <groupId>org.springframework.boot</groupId>
47 <artifactId>spring-boot-starter-test</artifactId>
48 </dependency>
49 <!-- 修改后立即生效,热部署 -->
50 <dependency>
51 <groupId>org.springframework</groupId>
52 <artifactId>springloaded</artifactId>
53 </dependency>
54 <dependency>
55 <groupId>org.springframework.boot</groupId>
56 <artifactId>spring-boot-devtools</artifactId>
57 </dependency>
58 </dependencies>
59
60</project>
61
在microservice-provider微服找那个需要引用microservice-com微服中User bean,所以在pom文件中引入了microservice-com的依赖。
1
2
3
4
5
6
7 1
2<dependency>
3 <groupId>com.hjp.springcloud</groupId>
4 <artifactId>microservice-com</artifactId>
5 <version>${project.version}</version>
6 </dependency>
7
3、在microservice-provider需要操作数据库,在application.yml中配置mybatis和数据源如下:
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 1server:
2 port: 8002
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10spring:
11 application:
12 name: microservicecloud-provider #微服务的名字
13 datasource:
14 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
15 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
16 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
17 username: root
18 password: root
19 dbcp2:
20 initial-size: 5 # 初始化连接数
21 max-total: 5 # 最大连接数
22 max-wait-millis: 200 # 等待连接获取的最大超时时间
23 min-idle: 5 # 数据库连接池的最小维持连接数
24
25
4、在src/main/resources目录下创建mybatis文件夹后新建mybatis.cfg.xml文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11 1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
3<configuration>
4
5 <!-- 开启二级缓存 -->
6 <settings>
7 <setting name="cacheEnabled" value="true"/>
8 </settings>
9
10</configuration>
11
5、创建Dao接口,用于操作user表的接口
1
2
3
4
5
6
7
8
9
10 1@Mapper
2public interface UserDao {
3
4 public boolean addUser(User user);
5
6 public User getUser(int id);
7
8 public List<User> getUsers();
9}
10
6、在src/main/resources/mybatis目录下创建mapper目录,并在mapper目录下创建UserMapper.xml文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3<mapper namespace="com.hjp.dao.UserDao">
4
5 <select id="getUser" resultType="User" parameterType="int">
6 select * from user where ID=#{id}
7 </select>
8
9 <select id="getUsers" resultType="User">
10 select * from user
11 </select>
12
13 <insert id="addUser" parameterType="User">
14 insert into user(NAME, AGE) values(#{name}, #{age})
15 </insert>
16
17</mapper>
18
7、创建UserService服务接口
1
2
3
4
5
6
7
8
9 1public interface UserService {
2
3 public boolean addUser(User user);
4
5 public User getUser(int id);
6
7 public List<User> getUsers();
8}
9
8、创建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 1@Service
2public class UserServiceImpl implements UserService {
3
4 @Autowired
5 private UserDao userDao;
6
7 @Override
8 public boolean addUser(User user) {
9 boolean flag;
10 flag = userDao.addUser(user);
11 return flag;
12 }
13
14 @Override
15 public User getUser(int id) {
16 User user = userDao.getUser(id);
17 return user;
18 }
19
20 @Override
21 public List<User> getUsers() {
22 List<User> users = userDao.getUsers();
23 return users;
24 }
25
26}
27
9、创建Controller层,用于相应REST请求
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 1@RestController
2public class UserController {
3
4 @Autowired
5 private UserService service;
6
7 @RequestMapping(value="/add", method=RequestMethod.POST)
8 public boolean addUser(@RequestBody User user){
9 boolean flag = service.addUser(user);
10 return flag;
11 }
12
13 @RequestMapping(value="/get/{id}", method=RequestMethod.GET)
14 public User getUser(@PathVariable("id") int id){
15 User user = service.getUser(id);
16 return user;
17 }
18
19 @RequestMapping(value="/getUser/list", method=RequestMethod.GET)
20 public List<User> getUsers(){
21 List<User> users = service.getUsers();
22 return users;
23 }
24}
25
10、创建microservice-provider的启动类
1
2
3
4
5
6
7
8
9
10
11 1
2@SpringBootApplication
3public class ProviderApplication {
4
5 public static void main(String[] args) {
6
7 SpringApplication.run(ProviderApplication.class, args);
8 }
9
10}
11
11、启动测试
四、建立microservice-consumer微服务
microservice-consumer服务用于请求microservice-provicer
创建与microservice-com类似,在microservice-parent下创建microservice-consumer微服。
1、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 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <parent>
4 <groupId>com.hjp.springcloud</groupId>
5 <artifactId>microservice-parent</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 </parent>
8 <artifactId>microservice-consumer</artifactId>
9
10 <dependencies>
11 <!-- 依赖microservice-com模块 -->
12 <dependency>
13 <groupId>com.hjp.springcloud</groupId>
14 <artifactId>microservice-com</artifactId>
15 <version>${project.version}</version>
16 </dependency>
17 <dependency>
18 <groupId>org.springframework.boot</groupId>
19 <artifactId>spring-boot-starter-web</artifactId>
20 </dependency>
21 <!-- 修改后立即生效,热部署 -->
22 <dependency>
23 <groupId>org.springframework</groupId>
24 <artifactId>springloaded</artifactId>
25 </dependency>
26 <dependency>
27 <groupId>org.springframework.boot</groupId>
28 <artifactId>spring-boot-devtools</artifactId>
29 </dependency>
30 </dependencies>
31</project>
32
热部署即为,工程每次修改完后,会重新部署。
2、application.yml配置文件如下:
配置访问端口
1
2
3 1server:
2 port: 8003
3
3、配置RestTemplate的bean
RestTemplate用于模拟发送REST的客户端请求
1
2
3
4
5
6
7
8
9 1@Configuration
2public class ConfigBean {
3
4 @Bean
5 public RestTemplate getRestTemplate(){
6 return new RestTemplate();
7 }
8}
9
3、配置controller层
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 1@RestController
2public class UserConsumerController {
3 private static String REST_URL_PREFIX = "http://localhost:8002";
4
5 @Autowired
6 private RestTemplate restTemplate;
7
8 @RequestMapping(value="/consumer/add")
9 public boolean addUser(User user){
10 Boolean flag = restTemplate.postForObject(REST_URL_PREFIX + "/add", user, Boolean.class);
11 return flag;
12 }
13
14 @RequestMapping(value="/consumer/get/{id}")
15 public User get(@PathVariable("id") int id){
16 User user = restTemplate.getForObject(REST_URL_PREFIX + "/get" + "/id", User.class);
17 return user;
18 }
19
20 @SuppressWarnings({ "unchecked", "rawtypes" })
21 @RequestMapping(value="/consumer/list")
22 public List<User> getList(){
23 List list = restTemplate.getForObject(REST_URL_PREFIX + "/getUser/list", List.class);
24 return list;
25 }
26}
27
4、创建启动类
1
2
3
4
5
6
7
8 1@SpringBootApplication
2public class ConsumerApplication {
3
4 public static void main(String[] args) {
5 SpringApplication.run(ConsumerApplication.class, args);
6 }
7
8
5、启动测试
五、建立microservice-eurake1微服务
eureka微服务用于注册和发现服务。
首先建立一个依赖于microservice-parent的microservice-eurake1工程,与上面建立方法一样。
1、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 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <parent>
4 <groupId>com.hjp.springcloud</groupId>
5 <artifactId>microservice-parent</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 </parent>
8
9 <artifactId>microservice-eurake1</artifactId>
10
11 <dependencies>
12 <!--eureka-server服务端 -->
13 <dependency>
14 <groupId>org.springframework.cloud</groupId>
15 <artifactId>spring-cloud-netflix-eureka-server</artifactId>
16 </dependency>
17 <!-- 修改后立即生效,热部署 -->
18 <dependency>
19 <groupId>org.springframework</groupId>
20 <artifactId>springloaded</artifactId>
21 </dependency>
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>spring-boot-devtools</artifactId>
25 </dependency>
26 </dependencies>
27
28</project>
29
2、application.yml文件配置如下
1
2
3
4
5
6
7
8
9
10
11
12 1eureka:
2 instance:
3 hostname: localhost
4 client:
5 register-with-eureka: false
6 fetch-registry: false
7 service-url:
8 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
9
10server:
11 port: 9001
12
3、创建启动类
1
2
3
4
5
6
7
8
9
10 1@SpringBootApplication
2@EnableEurekaServer
3public class EurekaApplication {
4
5 public static void main(String[] args) {
6 SpringApplication.run(EurekaApplication.class, args);
7 }
8
9}
10
注意,一定不要忘记@EnableEurekaServer注解,该注解用于激活eureka的服务端。
现在可以启动microservice-eureka微服务了
5、把microservice-provider微服务注册进microservice-eureka服务中
- 在microservice-provider微服务中的pom文件加入下面依赖
1
2
3
4
5
6
7
8
9
10
11 1<!-- 将微服务microservice-provider注册进eureka -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-eureka</artifactId>
5 </dependency>
6 <dependency>
7 <groupId>org.springframework.cloud</groupId>
8 <artifactId>spring-cloud-starter-config</artifactId>
9 </dependency>
10
11
microservice-provider中的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 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <parent>
4 <groupId>com.hjp.springcloud</groupId>
5 <artifactId>microservice-parent</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 </parent>
8
9 <artifactId>microservice-provider</artifactId>
10
11 <dependencies>
12 <dependency>
13 <groupId>com.hjp.springcloud</groupId>
14 <artifactId>microservice-com</artifactId>
15 <version>${project.version}</version>
16 </dependency>
17 <dependency>
18 <groupId>junit</groupId>
19 <artifactId>junit</artifactId>
20 </dependency>
21 <dependency>
22 <groupId>mysql</groupId>
23 <artifactId>mysql-connector-java</artifactId>
24 </dependency>
25 <dependency>
26 <groupId>com.alibaba</groupId>
27 <artifactId>druid</artifactId>
28 </dependency>
29 <dependency>
30 <groupId>ch.qos.logback</groupId>
31 <artifactId>logback-core</artifactId>
32 </dependency>
33 <dependency>
34 <groupId>org.mybatis.spring.boot</groupId>
35 <artifactId>mybatis-spring-boot-starter</artifactId>
36 </dependency>
37 <dependency>
38 <groupId>org.springframework.boot</groupId>
39 <artifactId>spring-boot-starter-jetty</artifactId>
40 </dependency>
41 <dependency>
42 <groupId>org.springframework.boot</groupId>
43 <artifactId>spring-boot-starter-web</artifactId>
44 </dependency>
45 <dependency>
46 <groupId>org.springframework.boot</groupId>
47 <artifactId>spring-boot-starter-test</artifactId>
48 </dependency>
49 <!-- 将微服务microservice-provider侧注册进eureka -->
50 <dependency>
51 <groupId>org.springframework.cloud</groupId>
52 <artifactId>spring-cloud-starter-eureka</artifactId>
53 </dependency>
54 <dependency>
55 <groupId>org.springframework.cloud</groupId>
56 <artifactId>spring-cloud-starter-config</artifactId>
57 </dependency>
58 <!-- 修改后立即生效,热部署 -->
59 <dependency>
60 <groupId>org.springframework</groupId>
61 <artifactId>springloaded</artifactId>
62 </dependency>
63 <dependency>
64 <groupId>org.springframework.boot</groupId>
65 <artifactId>spring-boot-devtools</artifactId>
66 </dependency>
67 </dependencies>
68
69</project>
70
在microservice-provider微服务中的application.yml文件中加入如下配置
表示把microservice-provider微服务注册进http://localhost:9001/eureka指示的服务中,即microservice-eureka微服务中。
1
2
3
4
5 1eureka:
2 client:
3 service-url:
4 defaultZone: http://localhost:9001/eureka
5
microservice-provider中application.yml配置文件如下:
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 1server:
2 port: 8002
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10
11spring:
12 application:
13 name: microservicecloud-provider #微服务的名字
14 datasource:
15 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
16 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
17 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
18 username: root
19 password: root
20 dbcp2:
21 initial-size: 5 # 初始化连接数
22 max-total: 5 # 最大连接数
23 max-wait-millis: 200 # 等待连接获取的最大超时时间
24 min-idle: 5 # 数据库连接池的最小维持连接数
25
26eureka:
27 client:
28 service-url:
29 defaultZone: http://localhost:9001/eureka
30
31
在microservice-provider微服务中的启动类上加入@EnableEurekaClient注解。表示microservice-provider微服务启动时就启动eureka的客户端,该客户端自动的把microservice-provider服务注册进microservice-eureka1中。
1
2
3
4
5
6
7
8
9
10
11 1@SpringBootApplication
2@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
3public class ProviderApplication {
4
5 public static void main(String[] args) {
6
7 SpringApplication.run(ProviderApplication.class, args);
8 }
9
10}
11
6、测试microservice-provider服务已经注册进了microservice-eureka1服务。
启动microservice-eureka1微服务,然后再启动microservice-provider微服务,
在浏览器中请求http://localhost:9001/,反馈网页如下:
可见网页中Application那一栏多了一个MICROSERVICECLOUD-PROVIDER服务,此处显示的服务名字是在microservice-provider服务中的application.yml文件中配置的
1
2
3
4 1spring:
2 application:
3 name: microservicecloud-provider #微服务的名字
4
7、修改注册服务的主机名称
我们看到在上述的测试中,注册进eureka中的MICROSERVICE-PROVIDER服务,在状态一栏里面显示的是主机名称:服务名称的形式,主机默认是我本人主机名称。
下面修改microservicecloud-provider中的application.yml文件,关于eureka的部分改为如下:
1
2
3
4
5
6
7
8 1eureka:
2 client:
3 service-url:
4 defaultZone: http://localhost:9001/eureka
5 instance:
6 instance-id: microservicecloud-provider8002
7
8
重启服务,状态栏中显示的即为配置的instance-id名称。
8、eureka中显示注册微服务的ip信息
当鼠标放在注册微服务的链接上,左下角显示注册微服务的ip信息
左下角显示了microservice-provider微服务的ip信息,要想达到此效果,只需要microservice-provider服务中application.yml中eureka的配置改为如下
1
2
3
4
5
6
7
8
9 1eureka:
2 client:
3 service-url:
4 defaultZone: http://localhost:9001/eureka
5 instance:
6 instance-id: microservicecloud-provider8002 #自定义服务名称信息
7 prefer-ip-address: true
8
9
9、点击注册微服务链接,显示微服务的info信息
下面定制当点击链接时,显示指定信息
首先在microservice-parent的pom中增加<build>的配置,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
95
96
97
98
99 1<?xml version="1.0" encoding="UTF-8"?>
2<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">
3
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>com.hjp.springcloud</groupId>
6 <artifactId>microservice-parent</artifactId>
7 <version>0.0.1-SNAPSHOT</version>
8 <packaging>pom</packaging>
9
10 <properties>
11 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12 <maven.compiler.source>1.8</maven.compiler.source>
13 <maven.compiler.target>1.8</maven.compiler.target>
14 <junit.version>4.12</junit.version>
15 <log4j.version>1.2.17</log4j.version>
16 <lombok.version>1.16.18</lombok.version>
17 </properties>
18
19
20 <dependencyManagement>
21 <dependencies>
22 <dependency>
23 <groupId>org.springframework.cloud</groupId>
24 <artifactId>spring-cloud-dependencies</artifactId>
25 <version>Dalston.SR1</version>
26 <type>pom</type>
27 <scope>import</scope>
28 </dependency>
29 <dependency>
30 <groupId>org.springframework.boot</groupId>
31 <artifactId>spring-boot-dependencies</artifactId>
32 <version>1.5.9.RELEASE</version>
33 <type>pom</type>
34 <scope>import</scope>
35 </dependency>
36 <dependency>
37 <groupId>mysql</groupId>
38 <artifactId>mysql-connector-java</artifactId>
39 <version>5.1.46</version>
40 </dependency>
41 <dependency>
42 <groupId>com.alibaba</groupId>
43 <artifactId>druid</artifactId>
44 <version>1.1.0</version>
45 </dependency>
46 <dependency>
47 <groupId>org.mybatis.spring.boot</groupId>
48 <artifactId>mybatis-spring-boot-starter</artifactId>
49 <version>1.3.0</version>
50 </dependency>
51 <dependency>
52 <groupId>ch.qos.logback</groupId>
53 <artifactId>logback-core</artifactId>
54 <version>1.2.3</version>
55 </dependency>
56 <dependency>
57 <groupId>junit</groupId>
58 <artifactId>junit</artifactId>
59 <version>${junit.version}</version>
60 <scope>test</scope>
61 </dependency>
62 <dependency>
63 <groupId>log4j</groupId>
64 <artifactId>log4j</artifactId>
65 <version>${log4j.version}</version>
66 </dependency>
67 </dependencies>
68 </dependencyManagement>
69
70 <build>
71 <finalName>microservicecloud</finalName>
72 <resources>
73 <resource>
74 <directory>src/main/resources</directory>
75 <filtering>true</filtering>
76 </resource>
77 </resources>
78 <plugins>
79 <plugin>
80 <groupId>org.apache.maven.plugins</groupId>
81 <artifactId>maven-resources-plugin</artifactId>
82 <configuration>
83 <delimiters>
84 <delimit>$</delimit>
85 </delimiters>
86 </configuration>
87 </plugin>
88 </plugins>
89 </build>
90
91 <modules>
92 <module>microservice-com</module>
93 <module>microservice-provider</module>
94 <module>microservice-consumer</module>
95 <module>microservice-eurake1</module>
96 </modules>
97</project>
98
99
然后再microservice-provider的服务中增加如下依赖
1
2
3
4
5 1<dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-actuator</artifactId>
4 </dependency>
5
最后在microservice-provider中application.yml中配置显示的info信息
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 1server:
2 port: 8002
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10
11spring:
12 application:
13 name: microservicecloud-provider #微服务的名字
14 datasource:
15 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
16 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
17 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
18 username: root
19 password: root
20 dbcp2:
21 initial-size: 5 # 初始化连接数
22 max-total: 5 # 最大连接数
23 max-wait-millis: 200 # 等待连接获取的最大超时时间
24 min-idle: 5 # 数据库连接池的最小维持连接数
25
26eureka:
27 client:
28 service-url:
29 defaultZone: http://localhost:9001/eureka
30 instance:
31 instance-id: microservicecloud-provider8002 #自定义服务名称信息
32 prefer-ip-address: true #访问路径可以显示IP地址
33
34info:
35 app.name: microservicecloud-provider
36 company.name: www.lzj.com
37 build.artifactId: $project.artifactId$
38 build.version: $project.version$
39
40
重启microservice-eurake1和microservicecloud-provider微服务,点击注册的微服务microservicecloud-provider的链接,查看效果。
10、eureka的自我保护
过段时间,微服务没有用时,会出现下面红色的警告信息,即为eureka的自我保护。
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false 禁用自我保护模式。
六、建立eureka集群
第五步只是建立了一个eureka的微服务,如果当这个微服务down掉了,那么其它微服务就不能被注册和发现,整个系统就会down掉,所以下面建立多个eureka微服务,配置eureka集群,需要注册的微服务要注册到所有的eureka的微服务中,即注册到整个集群上,当一个eureka的微服务挂掉了,其它的eureka微服可以继续工作。
首先修改host文件,添加127.0.0.1的多个域名映射,方便后面模拟根据多个地址进行注册服务。
分别复制microservice-eurake1工程为microservice-eurake2和microservice-eurake3,
把microservice-eurake2服务中pom文件中的artifactId改为(因为之前该微服是复制过来的,如果是创建过来的就不用修改)<artifactId>microservice-eurake2</artifactId>
把microservice-eurake3服务中pom文件中的artifactId改为<artifactId>microservice-eurake3</artifactId>
修改microservice-eureka1的application.yml文件为
1
2
3
4
5
6
7
8
9
10
11
12 1eureka:
2 instance:
3 hostname: localhost
4 client:
5 register-with-eureka: false
6 fetch-registry: false
7 service-url:
8 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
9 defaultZone: http://eureka9003.com:9003/eureka/,http://eureka9002.com:9002/eureka/
10server:
11 port: 9001
12
修改microservice-eureka2的application.yml文件为
1
2
3
4
5
6
7
8
9
10
11
12 1eureka:
2 instance:
3 hostname: localhost
4 client:
5 register-with-eureka: false
6 fetch-registry: false
7 service-url:
8 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
9 defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9003.com:9003/eureka/
10server:
11 port: 9002
12
修改microservice-eureka3的application.yml文件为
1
2
3
4
5
6
7
8
9
10
11
12
13 1eureka:
2 instance:
3 hostname: localhost
4 client:
5 register-with-eureka: false
6 fetch-registry: false
7 service-url:
8 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
9 defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
10
11server:
12 port: 9003
13
然后修改microservice-provider微服务application.yml中的defaultZone配置,把该微服务同时注册到三个eureka微服务中,即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 1server:
2 port: 8002
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10
11spring:
12 application:
13 name: microservicecloud-provider #微服务的名字
14 datasource:
15 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
16 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
17 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
18 username: root
19 password: root
20 dbcp2:
21 initial-size: 5 # 初始化连接数
22 max-total: 5 # 最大连接数
23 max-wait-millis: 200 # 等待连接获取的最大超时时间
24 min-idle: 5 # 数据库连接池的最小维持连接数
25
26eureka:
27 client:
28 service-url:
29 #defaultZone: http://localhost:9001/eureka
30 defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9003.com:9003/eureka/
31 instance:
32 instance-id: microservicecloud-provider8002 #自定义服务名称信息
33 prefer-ip-address: true #访问路径可以显示IP地址
34
35info:
36 app.name: microservicecloud-provider
37 company.name: www.lzj.com
38 build.artifactId: $project.artifactId$
39 build.version: $project.version$
40
测试:运行microservice-eurake1、microservice-eurake2、microservice-eurake3、microservice-provider
从浏览器中访问eureka1的管理端http://localhost:9001/
可以看出,两个划横线的为microservice-eurake1的备份,microservice-provider为注册上来的服务。eureka的3个微服务组成了一个服务注册的集群,只有有一个能工作,能保证业务的执行
七、Ribbon负载均衡
Ribbon的负载均衡是应用于客户端的,即调用一方的,在本案例中就是应用于microservice-consumer微服务的,下面就对microservice-consumer微服务使用负载均衡。
1、microservice-consumer进行Ribbon配置
下面进行修改microservice-consumer微服务的配置
pom文件中增加Ribbon需要的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1<!-- Ribbon相关 -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-eureka</artifactId>
5 </dependency>
6 <dependency>
7 <groupId>org.springframework.cloud</groupId>
8 <artifactId>spring-cloud-starter-ribbon</artifactId>
9 </dependency>
10 <dependency>
11 <groupId>org.springframework.cloud</groupId>
12 <artifactId>spring-cloud-starter-config</artifactId>
13 </dependency>
14
15
修改application.yml文件,增加eureka的服务注册功能,修改后的配置如下
1
2
3
4
5
6
7
8
9
10 1server:
2 port: 8003
3
4eureka:
5 client:
6 register-with-eureka: false
7 service-url:
8 defaultZone: http://eureka9003.com:9003/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9001.com:9001/eureka/
9
10
负载均衡实际是根据RestTemplate根据均衡算法进行调度不同地址上的同一个微服务的部署。所以修改ConfigBean,在RestTemplate上加@LoadBalanced注解。
1
2
3
4
5
6
7
8
9
10 1@Configuration
2public class ConfigBean {
3
4 @Bean
5 @LoadBalanced
6 public RestTemplate getRestTemplate(){
7 return new RestTemplate();
8 }
9}
10
把microservice-consumer也注册到eureka服务中,需要在启动类上加@EnableEurekaClient注解
1
2
3
4
5
6
7
8
9
10 1@SpringBootApplication
2@EnableEurekaClient
3public class ConsumerApplication {
4
5 public static void main(String[] args) {
6 SpringApplication.run(ConsumerApplication.class, args);
7 }
8
9}
10
修改controller层,不再通过地址和端口调取其它微服的应用,而是根据微服务的名来调取应用。修改后如下
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 1@RestController
2public class UserConsumerController {
3// private static String REST_URL_PREFIX = "http://localhost:8002";
4 /*直接根据微服务名调用,而不再是根据地址和端口了,运用了eureka的发现功能*/
5 private static String REST_URL_PREFIX = "http://microservicecloud-provider";
6
7 @Autowired
8 private RestTemplate restTemplate;
9
10 @RequestMapping(value="/consumer/add")
11 public boolean addUser(User user){
12 Boolean flag = restTemplate.postForObject(REST_URL_PREFIX + "/add", user, Boolean.class);
13 return flag;
14 }
15
16 @RequestMapping(value="/consumer/get/{id}")
17 public User get(@PathVariable("id") int id){
18 User user = restTemplate.getForObject(REST_URL_PREFIX + "/get/" + id, User.class);
19 return user;
20 }
21
22 @SuppressWarnings({ "unchecked", "rawtypes" })
23 @RequestMapping(value="/consumer/list")
24 public List<User> getList(){
25 List list = restTemplate.getForObject(REST_URL_PREFIX + "/getUser/list", List.class);
26 return list;
27 }
28}
29
只是修改了private static String REST_URL_PREFIX = “http://microservicecloud-provider”;
测试:修改上述配置后,下面进行测试,启动microservice-eurake1、microservice-eurake2、microservice-eurake3微服务,然后启动microservice-provider提供者微服务,最后启动带Ribbon负载均衡配置的消费者(客户端)微服务microservice-consumer。
启动测试。
说明可以从消费端通过微服务名找到提供者微服务,然后进行调用。
2、Ribbon负载均衡
上面在消费端microservice-consumer配置好了Ribbon,提供者微服务目前只有一个。为减小提供者微服务的压力,现在再部署两个提供者微服务,当客户端发送请求时,由三个微服务中的一个随机的响应请求。
复制microservice-provider工程生成microservice-provider2和microservice-provider3
修改microservice-provider2的启动类为ProviderApplication2
修改microservice-provider3的启动类为ProviderApplication3
修改microservice-provider2的application.yml配置为
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 1server:
2 port: 8003
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10
11spring:
12 application:
13 name: microservicecloud-provider #微服务的名字
14 datasource:
15 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
16 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
17 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
18 username: root
19 password: root
20 dbcp2:
21 initial-size: 5 # 初始化连接数
22 max-total: 5 # 最大连接数
23 max-wait-millis: 200 # 等待连接获取的最大超时时间
24 min-idle: 5 # 数据库连接池的最小维持连接数
25
26eureka:
27 client:
28 service-url:
29 #defaultZone: http://localhost:9001/eureka
30 defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9003.com:9003/eureka/
31 instance:
32 instance-id: microservicecloud-provider8003 #自定义服务名称信息
33 prefer-ip-address: true #访问路径可以显示IP地址
34
35info:
36 app.name: microservicecloud-provider
37 company.name: www.lzj.com
38 build.artifactId: $project.artifactId$
39 build.version: $project.version$
40
41
修改microservice-provider3的配置为
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 1server:
2 port: 8004
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10
11spring:
12 application:
13 name: microservicecloud-provider #微服务的名字
14 datasource:
15 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
16 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
17 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
18 username: root
19 password: root
20 dbcp2:
21 initial-size: 5 # 初始化连接数
22 max-total: 5 # 最大连接数
23 max-wait-millis: 200 # 等待连接获取的最大超时时间
24 min-idle: 5 # 数据库连接池的最小维持连接数
25
26eureka:
27 client:
28 service-url:
29 #defaultZone: http://localhost:9001/eureka
30 defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9003.com:9003/eureka/
31 instance:
32 instance-id: microservicecloud-provider8004 #自定义服务名称信息
33 prefer-ip-address: true #访问路径可以显示IP地址
34
35info:
36 app.name: microservicecloud-provider
37 company.name: www.lzj.com
38 build.artifactId: $project.artifactId$
39 build.version: $project.version$
40
41
只是分别修改了server.port和eureka.instance.instance-id。
为方便观察哪一个提供者微服务响应的客户端请求,在提供者微服中分别打印两条日志,
microservice-provider微服务中UserServiceImpl类中getUser方法修改为如下
1
2
3
4
5
6
7
8 1@Override
2 public User getUser(int id) {
3 User user = userDao.getUser(id);
4 System.out.println("microservice-provider微服务在响应客户端请求……");
5 System.out.println("user : " + user);
6 return user;
7 }
8
microservice-provider2微服务中UserServiceImpl类中getUser方法修改为如下
1
2
3
4
5
6
7
8 1@Override
2 public User getUser(int id) {
3 User user = userDao.getUser(id);
4 System.out.println("microservice-provider2微服务在响应客户端请求……");
5 System.out.println("user : " + user);
6 return user;
7 }
8
microservice-provider3微服务中UserServiceImpl类中getUser方法修改为如下:
1
2
3
4
5
6
7
8 1@Override
2 public User getUser(int id) {
3 User user = userDao.getUser(id);
4 System.out.println("microservice-provider3微服务在响应客户端请求……");
5 System.out.println("user : " + user);
6 return user;
7 }
8
测试:启动3个eureka的微服务集群,然后启动3个上述提供者微服务,最后启动消费者微服务microservice-consumer,分别从前端发起http://localhost:7001/consumer/get/{id}多笔请求,id用数字代替,发现分别在三个提供者服务的console中输出如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13 1microservice-provider3微服务在响应客户端请求……
2user : User [id=1, name=lzj1, age=20]
3
4microservice-provider3微服务在响应客户端请求……
5user : User [id=2, name=lzj2, age=24]
6
7microservice-provider微服务在响应客户端请求……
8user : User [id=4, name=lzj4, age=30]
9
10microservice-provider2微服务在响应客户端请求……
11user : User [id=3, name=lzj3, age=26]
12
13
3个提供者微服务随机的响应客户端请求。
3、通过Ribbon的核心组件IRule定义查找消费端调用提供端微服务的策略
如没有指定轮询策略,默认是消费端随机调用提供端微服的策略,下面指定轮询调用策略。只需要在microservice-consumer中的ConfigBean类添加如下声明:
1
2
3
4
5 1@Bean
2 public IRule myRule(){
3 return new RoundRobinRule(); //轮询策略
4 }
5
重新启动3个eureka微服务和3个提供者微服务,最后启动消费者微服务,重新测试,可知消费者微服务是轮询调用提供者的3个微服务的。
八、Feign负载均衡
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。Feign是对Ribbon的包装,Feign集成了Ribbon。
前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
Feign既然是对Ribbon的包装,那么Feign也是用在客户端的,即消费端的。下面建立集成Feign的消费端
复制microservice-consumer工程为microservice-consumer-feign
修改microservice-consumer-feign启动类的名字为FeignConsumerApplication;
microservice-consumer-feign的pom文件中增加对Feign的依赖:
1
2
3
4
5 1<dependency>
2 <groupId>org.springframework.cloud</groupId>
3 <artifactId>spring-cloud-starter-feign</artifactId>
4 </dependency>
5
创建ConsumerService接口,用于包装microservicecloud-provider微服务,以后要调用microservicecloud-provider服务中的方法,只需要调用接口中对应的方法即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1/*以后调用microservicecloud-provider微服务中的方法,只需要调用下面对应的接口既可以了*/
2@FeignClient(value="microservicecloud-provider")
3public interface ConsumerService {
4
5 /*调用接口中的get方法,即可以向microservicecloud-provider微服务发送/get/{id}请求*/
6 @RequestMapping(value="/get/{id}", method=RequestMethod.GET)
7 public User get(@PathVariable("id") int id);
8
9 @RequestMapping(value="/add", method=RequestMethod.POST)
10 public boolean add(User user);
11
12 @RequestMapping(value="/getUser/list", method=RequestMethod.GET)
13 public List<User> getAll();
14}
15
修改microservice-consumer-feign中的controller层为
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 1@RestController
2public class UserConsumerController {
3// private static String REST_URL_PREFIX = "http://localhost:8002";
4 /*直接根据微服务名调用,而不再是根据地址和端口了,运用了eureka的发现功能*/
5// private static String REST_URL_PREFIX = "http://microservicecloud-provider";
6// @Autowired
7// private RestTemplate restTemplate;
8
9 @Autowired
10 private ConsumerService service;
11
12 @RequestMapping(value="/consumer/add")
13 public boolean addUser(User user){
14 Boolean flag = service.add(user);
15 return flag;
16 }
17
18 @RequestMapping(value="/consumer/get/{id}")
19 public User get(@PathVariable("id") int id){
20 User user = service.get(id);
21 return user;
22 }
23
24 @SuppressWarnings({ "unchecked", "rawtypes" })
25 @RequestMapping(value="/consumer/list")
26 public List<User> getList(){
27 List list = service.getAll();
28 return list;
29 }
30}
31
修改启动类FeignConsumerApplication,在启动类上加启用Feign的注解:
1
2
3
4
5
6
7
8
9
10
11 1@SpringBootApplication
2@EnableEurekaClient
3@EnableFeignClients(basePackages="com.lzj.springcloud.service")
4public class FeignConsumerApplication {
5
6 public static void main(String[] args) {
7 SpringApplication.run(FeignConsumerApplication.class, args);
8 }
9
10}
11
测试,启动microservice-eurake1、microservice-eurake2、microservice-eurake3集群,然后启动microservice-provider、microservice-provider2、microservice-provider3集群,最后启动microservice-consumer-feign微服务。
从浏览器中向消费端发送请求http://localhost:7001/consumer/get/2
Feign通过接口ConsumerService中的get方法调用Rest服务(之前是通过Ribbon+RestTemplate),并在eureka微服务中查找microservicecloud-provider服务,找到后,把请求http://localhost:7001/consumer/get/2发送到microservicecloud-provider微服务。
九、Hystrix断路器
如果一个请求需要调起多个服务时,其中一个服务不通或失败,当大量请求发生时,会导致请求延时和资源浪费。Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
Hystrix可用于服务熔断、服务降级、服务限流等作用。
1、服务熔断
当某个服务出现异常时,熔断该服务,快速返回指定的错误信息,当服务正常时,恢复熔断。
复制microservice-provider工程为microservice-provider-hystrix;
修改microservice-provider-hystrix的启动类为HystrixProviderApplication;
pom文件中添加hystrix的依赖
1
2
3
4
5
6
7 1<!-- hystrix -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-hystrix</artifactId>
5 </dependency>
6
7
application.yml配置如下:
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 1server:
2 port: 8005
3
4mybatis:
5 config-location: "classpath:mybatis/mybatis.cfg.xml" # mybatis配置文件所在路径
6 mapper-locations:
7 - "classpath:mybatis/mapper/**/*.xml" # mapper映射文件
8 type-aliases-package: com.hjp.entity # 别名类所在包
9
10
11spring:
12 application:
13 name: microservicecloud-provider #微服务的名字
14 datasource:
15 driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
16 type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
17 url: "jdbc:mysql://localhost:3306/hjp" # 数据库名称
18 username: root
19 password: root
20 dbcp2:
21 initial-size: 5 # 初始化连接数
22 max-total: 5 # 最大连接数
23 max-wait-millis: 200 # 等待连接获取的最大超时时间
24 min-idle: 5 # 数据库连接池的最小维持连接数
25
26eureka:
27 client:
28 service-url:
29 #defaultZone: http://localhost:9001/eureka
30 defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9003.com:9003/eureka/
31 instance:
32 instance-id: microservicecloud-provider-hystrix #自定义服务名称信息
33 prefer-ip-address: true #访问路径可以显示IP地址
34
35info:
36 app.name: microservicecloud-provider
37 company.name: www.lzj.com
38 build.artifactId: $project.artifactId$
39 build.version: $project.version$
40
41
只修改了server.port和eureka.instance.instance-id;
修改UserController内容为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 1@RestController
2public class UserController {
3
4 @Autowired
5 private UserService service;
6
7 @RequestMapping(value="/get/{id}", method=RequestMethod.GET)
8 @HystrixCommand(fallbackMethod="hystrixGetUser") //一旦服务调用失败,就调用hystrixGetUser方法
9 public User getUser(@PathVariable("id") int id){
10 User user = service.getUser(id);
11 if(user == null){
12 throw new RuntimeException("不存在id=" + id + "对应的用户信息");
13 }
14 return user;
15 }
16
17 public User hystrixGetUser(@PathVariable("id") int id){
18 User user = new User(id, "不存在该用户", 0);
19 return user;
20 }
21
22
在启动类HystrixProviderApplication上添加注解@EnableCircuitBreaker;
启动microservice-eurake1、microservice-eurake2、microservice-eurake3服务,然后启动microservice-provider-hystrix服务,然后启动microservice-consumer-feign服务。
测试:从浏览器中发送请求:http://localhost:7001/consumer/get/18,
2、服务降级
在一个分布式系统中,当访问高峰期或资源有限时,需要关掉某个服务,若有请求访问该服务,不能因为系统服务关掉了,就一直中断在该调用服务处,这时就需要请求返回指定的错误信息。例如在分布式系统中有A、B两个服务,因为资源有限,需要关掉B服务,A服务在调用B服务时,没有调通,此时A返回指定的错误信息,注意不是在B服务端返回的,是A客户端返回的错误信息。看示例
复制microservice-consumer-feign服务为microservice-consumer-feign-hystrix;
microservice-consumer-feign-hystrix的pom文件中添加依赖:
1
2
3
4
5
6
7 1<!-- hystrix -->
2 <dependency>
3 <groupId>org.springframework.cloud</groupId>
4 <artifactId>spring-cloud-starter-hystrix</artifactId>
5 </dependency>
6
7
microservice-consumer-feign-hystrix服务中新建实现FallbackFactory的ConsumerServiceFallbackFactory类,在类上添加@Component,并传入ConsumerService接口,当调用ConsumerService中对应的方法失败后,自动调用ConsumerServiceFallbackFactory 中对应实现的ConsumerService方法,并在对应方法中定制调用服务失败后显示的错误信息。
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 1@Component
2public class ConsumerServiceFallbackFactory implements FallbackFactory<ConsumerService> {
3
4 @Override
5 public ConsumerService create(Throwable arg0) {
6 // TODO Auto-generated method stub
7 return new ConsumerService() {
8
9 @Override
10 public List<User> getAll() {
11 // TODO Auto-generated method stub
12 return null;
13 }
14
15 @Override
16 public User get(int id) {
17 User user = new User(id, "该用户不存在", 0);
18 return user;
19 }
20
21 @Override
22 public boolean add(User user) {
23 // TODO Auto-generated method stub
24 return false;
25 }
26 };
27 }
28
29
在microservice-consumer-feign-hystrix服务中ConsumerService的接口中@FeignClient中添加fallbackFactory属性。运用spring的AOP切面,当调用ConsumerService中方法失败后,执行fallbackFactory属性指定的ConsumerServiceFallbackFactory类中的对应方法,ConsumerService修改后如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1/*以后调用microservicecloud-provider微服务中的方法,只需要调用下面对应的接口既可以了*/
2@FeignClient(value="microservicecloud-provider", fallbackFactory=ConsumerServiceFallbackFactory.class)
3public interface ConsumerService {
4
5 /*调用接口中的get方法,即可以向microservicecloud-provider微服务发送/get/{id}请求*/
6 @RequestMapping(value="/get/{id}", method=RequestMethod.GET)
7 public User get(@PathVariable("id") int id);
8
9 @RequestMapping(value="/add", method=RequestMethod.POST)
10 public boolean add(User user);
11
12 @RequestMapping(value="/getUser/list", method=RequestMethod.GET)
13 public List<User> getAll();
14}
15
修改microservice-consumer-feign-hystrix服务的application.yml文件为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1server:
2 port: 7001
3
4feign:
5 hystrix:
6 enabled: true
7
8eureka:
9 client:
10 register-with-eureka: false
11 service-url:
12 defaultZone: http://eureka9003.com:9003/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9001.com:9001/eureka/
13
14
测试:首先启动microservice-eurake1、microservice-eurake2、microservice-eurake3集群服务,然后启动microservice-provider提供者服务,最后启动microservice-consumer-feign-hystrix消费者服务。从浏览器中发送请求
http://localhost:7001/consumer/get/2
下面模拟资源有限,关掉microservice-provider提供者服务,关掉提供者服务后,重新在浏览器中发送请求http://localhost:7001/consumer/get/2
响应过程如下:当发送请求后,调用microservice-consumer-feign-hystrix服务中的UserConsumerController的get方法,然后调用ConsumerService中的get方法,该方法向microservice-provider服务发送请求/get/{id},由于microservice-provider服务被关掉了,请求失败,转而调用ConsumerServiceFallbackFactory中实现的对应方法
1
2
3
4
5
6 1@Override
2 public User get(int id) {
3 User user = new User(id, "该用户不存在", 0);
4 return user;
5 }
6
3、服务监控
hystrix除了应用于上述的服务熔断和降级,还可以应用于服务的实时监控。Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。示例如下
创建microservice-consumer-hystrix-dashbord微服务;
添加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 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <parent>
4 <groupId>com.hjp.springcloud</groupId>
5 <artifactId>microservice-parent</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 </parent>
8 <artifactId>microservice-consumer</artifactId>
9
10 <dependencies>
11 <dependency>
12 <groupId>org.springframework.boot</groupId>
13 <artifactId>spring-boot-starter-web</artifactId>
14 </dependency>
15 <dependency>
16 <groupId>org.springframework.cloud</groupId>
17 <artifactId>spring-cloud-starter-hystrix</artifactId>
18 </dependency>
19 <dependency>
20 <groupId>org.springframework.cloud</groupId>
21 <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
22 </dependency>
23 <!-- 修改后立即生效,热部署 -->
24 <dependency>
25 <groupId>org.springframework</groupId>
26 <artifactId>springloaded</artifactId>
27 </dependency>
28 <dependency>
29 <groupId>org.springframework.boot</groupId>
30 <artifactId>spring-boot-devtools</artifactId>
31 </dependency>
32 </dependencies>
33</project>
34
application.yml配置文件如下:
1
2
3 1server:
2 port: 7002
3
创建启动类HystrixDashbordConsumerApplication:
1
2
3
4
5
6
7
8
9
10 1@SpringBootApplication
2@EnableHystrixDashboard
3public class HystrixDashbordConsumerApplication {
4
5 public static void main(String[] args) {
6 SpringApplication.run(HystrixDashbordConsumerApplication.class, args);
7 }
8
9}
10
然后启动微服务,响应页面如下,说明创建用于监控其它服务的微服务成功:
测试:
首先启动microservice-eurake1、microservice-eurake2、microservice-eurake3集群服务,然后启动microservice-provider-hystrix服务,最后启动刚创建监控服务的服务microservice-consumer-hystrix-dashbord。
本例要监听提供者microservice-provider-hystrix服务的访问情况,下面把监控提供者服务的链接填入豪猪监控客户端中,如下
填入完毕后,点击Monitor stream按钮,开启监控页面。
从浏览器中连续的发送请求http://localhost:8005/get/1(不停的刷新即可),监控页面如下:
图中的实心圆的颜色为绿色,表示健康,健康程度排序绿色>黄色>橙色>红色,绿色表示最健康,红色表示最不健康。实心圆的大小表示了监控的服务访问量的大小,访问量越大,实心圆越大,反之,越小。图中每个颜色数字表示如下
十、Zuul路由
Zuul路由包含了对请求的路由和过滤两个功能。
路由:路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口;
过滤:过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。
Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获得其他微服务的消息,也即以后的访问微服务都是通过Zuul跳转后获得。Zuul服务最终也会注册进Eureka。
1、路由配置
建立一个microservice-zull微服务;
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 1<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">
2 <modelVersion>4.0.0</modelVersion>
3 <parent>
4 <groupId>com.hjp.springcloud</groupId>
5 <artifactId>microservice-parent</artifactId>
6 <version>0.0.1-SNAPSHOT</version>
7 </parent>
8 <artifactId>microservice-zull</artifactId>
9
10 <dependencies>
11 <!-- zuul路由网关 -->
12 <dependency>
13 <groupId>org.springframework.cloud</groupId>
14 <artifactId>spring-cloud-starter-eureka</artifactId>
15 </dependency>
16 <dependency>
17 <groupId>org.springframework.cloud</groupId>
18 <artifactId>spring-cloud-starter-zuul</artifactId>
19 </dependency>
20 <!-- 热部署插件 -->
21 <dependency>
22 <groupId>org.springframework</groupId>
23 <artifactId>springloaded</artifactId>
24 </dependency>
25 <dependency>
26 <groupId>org.springframework.boot</groupId>
27 <artifactId>spring-boot-devtools</artifactId>
28 </dependency>
29 </dependencies>
30
31
32</project>
33
也要把Zuul微服务注册到Eureaka上面,application.yml文件配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1server:
2 port: 6001
3
4spring:
5 application:
6 name: microservice-zull
7eureka:
8 client:
9 service-url:
10 defaultZone: http://eureka9003.com:9003/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9001.com:9001/eureka/
11 instance:
12 instance-id: microservice-zull6001 #自定义服务名称信息
13 prefer-ip-address: true #访问路径可以显示IP地址
14
15info:
16 app.name: microservice-zull
17 company.name: www.lzj.com
18 build.artifactId: $project.artifactId$
19 build.version: $project.version$
20
在host文件中添加127.0.0.1的映射,127.0.0.1 zull6001.com用zull6001.com表示Zuul微服务的域名;
创建ZullApplication启动类,内容如下:
1
2
3
4
5
6
7
8
9
10 1@SpringBootApplication
2@EnableZuulProxy //启动Zuul
3public class ZullApplication {
4
5 public static void main(String[] args) {
6 SpringApplication.run(ZullApplication.class, args);
7 }
8
9}
10
测试:
在浏览器中发送http://localhost:8002/get/2请求,直接请求microservice-provider微服务
在浏览器中发送http://zull6001.com:6001/microservicecloud-provider/get/2请求,通过Zuul路由访问microservicecloud-provider服务,其中zull6001.com:6001为microservice-zull微服务的域名和端口,microservicecloud-provider为要访问的微服务名(在application.yml中配置的)
2、修改服务代理名称
上面通过路由访问服务的请求为http://zull6001.com:6001/microservicecloud-provider/get/2,其中microservicecloud-provider为调用的服务名,向调用方暴露了具体的服务名。如果不想暴露服务名,可以为服务指定一个代号别名,例如可以通过发送请求http://zull6001.com:6001/provider/get/2访问microservicecloud-provider服务,那么provider即为microservicecloud-provider的别名,在application.yml中配置如下:
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 1server:
2 port: 6001
3
4spring:
5 application:
6 name: microservice-zull
7eureka:
8 client:
9 service-url:
10 defaultZone: http://eureka9003.com:9003/eureka/,http://eureka9002.com:9002/eureka/,http://eureka9001.com:9001/eureka/
11 instance:
12 instance-id: microservice-zull6001 #自定义服务名称信息
13 prefer-ip-address: true #访问路径可以显示IP地址
14
15zuul:
16 routes:
17 mydept.serviceId: microservicecloud-provider
18 mydept.path: /provider/**
19
20info:
21 app.name: microservice-zull
22 company.name: www.lzj.com
23 build.artifactId: $project.artifactId$
24 build.version: $project.version$
25
添加了关于zuul的配置,在浏览器中发送http://zull6001.com:6001/provider/get/2请求
响应正常,此时通过发送带调用的微服务名的请求也是可以访问的。
3、忽略带真实服务名的请求
如果想拒绝访问中带服务名的请求,例如http://zull6001.com:6001/microservicecloud-provider/get/2,使其不能再访问服务,只能通过指定的别名进行访问服务。
在application.yml中关于zuul的配置修改为如下(增加了ignored-services):
1
2
3
4
5
6 1zuul:
2 ignored-services: microservicecloud-provider
3 routes:
4 mydept.serviceId: microservicecloud-provider
5 mydept.path: /provider/**
6
4、设置访问前缀
当设置完忽略真实服务名访问后,只能通过路由代理别名的形式进行访问,例如http://zull6001.com:6001/provider/get/2,如果要在每次访问的时候,在代理服务名前面加一个前缀,例如http://zull6001.com:6001/MyDemo/provider/get/2,MyDemo即为前缀。在application.yml中关于zuul的配置修改为如下(只是添加了prefix的配置):
1
2
3
4
5
6
7 1zuul:
2 prefix: /MyDemo
3 ignored-services: microservicecloud-provider
4 routes:
5 mydept.serviceId: microservicecloud-provider
6 mydept.path: /provider/**
7