SpringBoot整合SpringCloud分布式服务

一、SpringCloud是什么

度娘:Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署

个人理解:可以发现SringCloud拥有服务发现注册、负载均衡的功能,而这两个功能,正好是dubbo所具有的功能,SpringCloud的出现,目的就是消灭分布式框架被dubbo霸气独占的局面,SpringCloud在实现服务发现注册和管控的基础上,增加了配置中心、消息总线、负载均衡、断路器、数据监控等功能。

二、SpringCloud与Dubbo的功能对比

背景

Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点,经过不断优化,阿里把自己的核心框架对外进行开源使用,这也是阿里近几年在国内开源社区影响力较大的原因,毕竟阿里在开源社区不少做贡献,例如JStorm捐赠给Apache并加入Apache基金会等,阿里在国内眼中,已经不仅仅是一家电商公司,阿里的生态系统,让国人为之震撼,人工智能、智能点餐、无人酒店,让阿里逐步变成了一家科技领头公司。

Spring Cloud,从命名就可以知道,它是Spring Source的产物,Spring社区的强大背书可以说是Java企业界最有影响力的组织了,除了Spring Source之外,还有Pivotal和Netfix是其强大的后盾与技术输出。其中Netflix开源的整套微服务架构套件是Spring Cloud的核心。

如果拿Dubbo和Netflix对比,dubbo在国内的影响力无疑是最大的,而Netflix 面向的是国际,在国际影响力上,Netflix 无疑是大佬。无论出身如何,这些架构都能在处理分布式问题时,提供很大的帮助。

功能架构

下表是dubbot和SpringCloud功能架构对比表

包含功能 Dubbo SpringCloud
服务注册中心 Zookeeper Spring Cloud Netflix Eureka
服务调用方式 RPC REST API
服务网关 Spring Cloud Netflix Zuul
断路器 不完善 Spring Cloud Netflix Hystrix
分布式配置 Spring Cloud Config
服务跟踪 Spring Cloud Sleuth
消息总线 Spring Cloud Bus
数据流 Spring Cloud Stream
批量任务 Spring Cloud Task
more…… more…… more……

三、开始整合SpringCloud

搭建maven多模块工程(分别为服务注册中心工程eureka-server,服务提供者provider-ticket,服务消费者consumer-user),项目架构图如下

搭建父工程

1.搭建父工程SpringCloudDemo,pom文件配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yang.study</groupId>
<artifactId>SpringCloudDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>eureka-server</module>
<module>consumer-user</module>
<module>provider-ticket</module>
</modules>
<properties>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>
</project>

搭建服务注册中心

2.搭建服务注册中心ureka-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
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.yang.study</groupId>
<artifactId>SpringCloudDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.yang.study</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server</name>
<!-- 添加相关依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<!-- 注意这里表明为服务器端 -->
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

3.编写全局配置文件application.yml

1
2
3
4
5
6
7
8
9
10
server:
port: 8761
eureka:
instance:
hostname: eureka-server # eureka实例的主机名
client:
register-with-eureka: false #不把自己注册到eureka上
fetch-registry: false #不从eureka上来获取服务的注册信息--不检索服务
service-url:
defaultZone: http://localhost:8761/eureka/

4.在java文件夹下创建包名org.eureka.server,并创建服务启动类EurekaServerApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.eureka.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

5.启动服务启动类,浏览器访问localhost:8761,显示如下

编写服务提供者

6.创建服务提供者工程provider-ticket,看标题就知道,又是售票的,哈哈,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
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<groupId>com.yang.study</groupId>
<artifactId>provider-ticket</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider-ticket</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>
<!--这里表明为客户端 -->
<dependencies>
<!-- 添加web支持的starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

7.全局配置文件如下application.yml,Spring.application.name是应用的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#服务启动端口号
server:
port: 8002
spring:
application:
name: provider-ticket

#注册提供配置
eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用服务的ip地址
client:
service-url: #注册到指定的服务中心
defaultZone: http://localhost:8761/eureka/

8.创建常用包名(org.provider.controller\org.provider.service\org.provider.service\org.provider.service.impl),在service创建售票服务类接口。

1
2
3
4
5
6
7
8
9
10
package org.provider.service;

/**
* 售票类
* @author yzx96
*
*/
public interface TicketService{
public String buyTicket();
}

9.在service.impl创建服务实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.provider.service.impl;

import org.provider.service.TicketService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class TicketServiceImpl implements TicketService {
@Value("${server.port}")
private String port;
public String buyTicket() {
System.out.println(port);
return "《疯狂的石头》";
}

}

10.在controll创建控制器TicketController,自己测试接口是否可用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package org.provider.controller;
import org.provider.service.TicketService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TicketController {

@Autowired
private TicketService ticketService;

// SpringCloud 整合微服务时是按照轻量级的HTTP进行通信
@GetMapping("/ticket")
public String getTicker(){
return ticketService.buyTicket();

}
}

11.在ticket创建服务启动类ProviderApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.provider.ticket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableEurekaClient//本服务启动后会自动注册进eureka服务中
@ComponentScan("org.provider") //类似于Spring的基础类扫描包,用来扫描实体,接口和控制器
public class ProviderApplication {

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

12.右键启动服务启动类,查看启动日志

13.访问服务注册中心,查看

14.访问本地接口,看服务是否可用

编写服务消费者

15.创建服务消费者工程consumer-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
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<groupId>com.yang.study</groupId>
<artifactId>consumer-user</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer-user</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
</project>

16.消费者工程全局配置文件application.yml如下

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: consumer-user
server:
port: 8200

eureka:
instance:
prefer-ip-address: true # 注册服务的时候使用服务的ip地址
client:
service-url:
defaultZone: http://localhost:8761/eureka/

17.创建包名(org.consumer.control\org.consumer.user),编写控制器UserController,并注入RestTemplate对象,RestTemplate对象用于在SpringCloud发现服务并调用来用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.consumer.control;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
* @author yzx96
*
*/
@RestController
public class UserController {

@Autowired
RestTemplate restTemplate;

@GetMapping("/buy")
public String butTicket(String name){
String s = restTemplate.getForObject("http://PROVIDER-TICKET/ticket/", String.class);
return name+"购买了"+s;
}
}

18.编写消费者服务启动类ConsumerApplication,并运行

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 org.consumer.user;

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.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
@ComponentScan("org.consumer")
@EnableDiscoveryClient//开启发现服务功能
@SpringBootApplication
public class ConsumerApplication {

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

@LoadBalanced//开启负载均衡机制
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
// 用来发送http请求
}
}

19.查看服务注册中心

20.访问服务地址,进行消费者调用验证,验证成功图如下,SpringCloud搭建完成

四、总结注意点及源码下载地址

1.消费者和服务提供者的全局配置文件中需要配置注册中心的地址:为eureka.client.service-url-defaultZone

2.消费者调用服务提供者接口,采用RestTemplate对象,不懂的可以百度查一下

源码下载地址(gitHub)点击我下载,小心你的鼠标