SpringCloud概述
面向服务的架构,是一种程序开发架构的设计思想。它将不同的功能单元使用一个作为独立的程序运行,并且提供访问的入口(将这些单独运行的每个程序称为服务)。
一个SOA架构的web应用程序,是多个服务组成的!!!
SOA架构的思想就是用于实现,程序分布式的。所以我们也可以将SOA架构的思想理解为分布式架构的思想。
问题:以上SOA架构,这样的系统架构,有什么问题?
答:(1)无法检查服务的健康状态(服务是否可用)。
(2)无法对服务进行管理。
我们可以通过一个框架来,解决这些问题。那就是Spring Cloud。
Spring Cloud通过一个注册中心(Eureka),统一管理了整个分布式系统的服务接口。
所有的服务(子系统)在对外提供服务(接口)之前,必须要在注册中心中注册。我们开发人员就可以在注册中心中,查看整个分布式系统的所有服务!!
我们SOA概念中称为服务系统的东西,在Spring cloud有一个新的名字,叫实例(instance,实例系统)!
Springcloud是提供了一整套企业级分布式云应用的完美解决方案,能够结合Spring Boot、Spring其它组件,实现快速开发的目的。
企业级开发越来越倾向Spring生态体系。当然也包括SpringCloud了。
根据上图所示,我们学习Spring Cloud首先要学习什么东西呢?
答:(1)必须要将Eureka配置成功
(2)实例是如何将服务在Eureka注册的
(3)如何在Eureka查看整个分布式系统所有实例对外提供的服务(发现服务)
(4)实例域实例之间是如何通讯的(调用)
第一步:配置Eureka服务器
第二步:创建注册服务实例(Eureka客户端-注册服务@EnableEurekaClient)
第三步:创建发现服务实例(Eureka客户端-发现服务@EnableDiscoveryClient)
第四步:实现发现服务实例调用注册服务实例的示例。
--注意实现:
1.Eclipse配置SpringCloud必须先安装好 spring tool suite 插件。否则配置文件没有提示!!
2.Spring Cloud框架的jar都是由maven或者gradle构建工具获得的。我们主流使用的是Maven。所以创建的maven项目
注意事项:必须要勾上Eureka Server选项
--
我们需要将生成好的代码的pom.xml文件的依赖加入到我们的项目!!!!!
<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>cn.gzsxt.springcloud</groupId>
<artifactId>springcloud-demo-01-eureka</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.19.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- springcloud版本锁定-->
<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>
package cn.gzsxt.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
第四步:创建配置文件application.properties
#1.配置端口
server.port=5121
#2.配置eureka主机名,找到eureka所在的机器
eureka.instance.hostname=localhost
#3.是否将自身注册为服务false表示不注册
eureka.client.register-with-eureka=false
#4.是否主动发现服务false表示不发现
eureka.client.fetch-registry=false
#5.对外提供的注册入口
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
注意事项:实例使用的是Spring Boot
--注意实现:必须添加webmvc模块以及Eureka客户端模块
--将生成的项目的pom.xml代码覆盖项目的pom.xml
<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>cn.gzsxt.springcloud</groupId>
<artifactId>springcloud-demo-02-instanceServer01</artifactId>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.19.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Edgware.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
--Application代码
package cn.gzsxt.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class InstanceApplication {
public static void main(String[] args) {
SpringApplication.run(InstanceApplication.class, args);
}
}
package cn.gzsxt.springcloud.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping("/say")
public String say(){
return "hello,springcloud";
}
}
第五步:编写配置文件application.properties
#指定实例端口
server.port=8080
#指定实例名,springcloud是通过实例名称来寻址服务的
spring.application.name=instanceServer
#指定Eureka服务端访问路径
eureka.client.service-url.defaultZone=http://localhost:5121/eureka
--注意事项:因为实例是Eureka的客户端,所以启动实例之前,必须要先启动Eureka服务端!
启动Eureka服务端
--启动Eureka服务端,启动成功,会暴露配置文件指定的5121端口
--测试Eureka服务端是否成功,在浏览器输入:http://localhost:5121
启动注册服务实例instanceServer01
--启动成功,会暴露配置文件指定的8080端口
--通过Eureka服务端管理后台可以查看客户端服务是否注册成功
第三部分:创建一个发现服务实例新实例(调用服务)
说明:将实例1复制一份。修改配置文件,修改为第二个实例
第二步:修改appplication.properties配置文件
#指定实例端口
server.port=8081
#指定实例名,springcloud是通过实例名称来寻址服务的
spring.application.name=instanceClient
#指定Eureka服务端访问路径
eureka.client.service-url.defaultZone=http://localhost:5121/eureka
@SpringBootApplication
//标记该项目为一个,该实例是一个发现服务的实例
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动实例2,确定实例在Eureka服务端注册时成功的。
--如果启动成功,会暴露一个application.xml配置文件指定的访问端口8081
第四部分:实现instanceClient与instanceServer的远程调用
需求:
(1)在instanceServer中,我们暴露一个login的远程restful接口。
(2)instanceClient调用该接口。将数据传递给它。
说明:SpringCloud远程服务调用,有两种实现方式:
(1)Ribbon+RestTemplate,基于restful实现。
其中,Ribbon是一个基于HTTP和TCP客户端的负载均衡器。
(2)Feign
其中,Feign默认启动Ribbon负载均衡。
步骤说明:(1)修改注册服务代码
(2)修改发现服务代码
(3)启动实例,实现服务调用
(4)负载均衡实现。
(1)创建User类
package cn.gzsxt.instance.pojo;
import java.io.Serializable;
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7260598142983180828L;
private Integer id;
private String username;
private String password;
//补全get、set方法
}
(2)修改UserController类,新增登录方法
package cn.gzsxt.instance.controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.gzsxt.instance.pojo.User;
@RestController
public class UserController {
/**
*用户登录
* @return
*/
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(@RequestBody User user){
System.out.println("用户名:"+user.getUsername()+",密码:"+user.getPassword());
return "Ok—intanceServer--8080";
}
}
第二步:修改发现服务实例instanceClient
(1)添加Ribbon依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
(2)修改Application启动类,标记该实例是发现服务实例
//1.用于启动Spring boot项目
@SpringBootApplication
//2.用于标识该项目是一个Eureka客户端(发现服务)
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//2.创建RestTemplate实例对象,用来远程调用服务
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
(3)创建UserService类
package cn.gzsxt.instance.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import cn.gzsxt.instance.pojo.User;
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public String login(User user){
String result = restTemplate.postForObject("http://instanceServer/login",user, String.class);
return result;
}
}
(4)修改UserController类
package cn.gzsxt.instance.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.gzsxt.instance.pojo.User;
import cn.gzsxt.instance.service.UserService;
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/login")
public String login(User user){
String result = userService.login(user);
System.out.println(result);
return result;
}
}
说明:依次启动注册中心、服务提供实例、服务发现实例。
(1)启动注册中心
(2)启动服务提供者
(4)启动服务发现者
(5)访问注册中心 http://localhost:5121/eureka
(6)访问服务发现实例
http://localhost:8081/login?username=root&password=123
远程服务调用成功!!!
第四步:基于ribbon负载均衡实现
负载均衡概念:在多个并且相同的服务可用的情况下,通过一定的负载策略,均衡的去调用这些服务,让服务到达一个平衡的状态。
重用的负载策略:轮询、权重、一致性ip等。
基于ribbon负载均衡实现步骤:
(1)创建一个新的注册服务实现instanceServer2。(复制instanceServer即可)
(2)修改instanceServer2的maven坐标
<groupId>cn.gzsxt.springcloud</groupId>
<artifactId>springcloud-demo-04-instanceServer2</artifactId>
<version>1.0</version>
(3)修改application.properties文件
说明:相同的服务,实例的名称也相同。
因此只用修改端口即可。
#指定实例端口
server.port=8082
#指定实例名
spring.application.name=instanceServer
#指定Eureka服务端访问路径
eureka.client.service-url.defaultZone=http://localhost:5121/eureka
(4)修改UserController代码
@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(@RequestBody User user){
System.out.println("用户名:"+user.getUsername()+",密码:"+user.getPassword());
return "Ok—intanceServer02--8082";
}
(5)启动实例
(6)多次访问登陆接口,查看结果
说明:在入门示例的基础上,复制一个新的发现服务实例instanceClient2。
步骤说明:(1)添加Feign客户端依赖
(2)修改服务发现代码
修改pom.xml文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
说明:Feign是基于interface接口来发现服务的。
package cn.gzsxt.instance.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.gzsxt.instance.pojo.User;
@FeignClient(name="instanceServer")
public interface UserService {
@RequestMapping(value="/login")
public String login(User user);
}
说明:添加Feign客户端支持 @EnableFeignClients
package cn.gzsxt.instance;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
//1.用于启动Spring boot项目
@SpringBootApplication
//2.用于标识该项目是一个Eureka客户端(发现服务)
@EnableDiscoveryClient
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
基于Feign远程访问成功!!!
在入门示例中,服务的注册、发现和调用,都是基于Eureka注册中心实现。
如果Eureka服务宕机了,整个服务就都不可用了。
解决的办法:
配置Eureka高可用,即配置多个Eureka服务器,当只要有一个Eureka还正常运行,就能够提供正常的服务。
第一步:先配置一个完整的Eureka服务器。
第二步:复制另外一个Eureka服务器。
第三步:修改两个Eureka的配置,实现这两个Eureka高可用。
--将第一个Eureka服务器复制一份,修改器配置为第二个Eureka服务。
<groupId>cn.gzsxt.springcloud</groupId>
<artifactId>springcloud-demo-01-eureka2</artifactId>
<version>1.0</version>
--修改第二个Eureka的服务端口,不要和第一个冲突。
#1.配置端口
server.port=5122
#2.配置eureka主机名
eureka.instance.hostname=localhost
#3.由于我们目前创建的应用是一个服务注册中心,而不是普通的应用,默认情况下,这个应用会向注册中心(也是它自己)注册它自己,设置为false表示禁止这种默认行为
eureka.client.register-with-eureka=false
#4.表示不去检索其他的服务,因为服务注册中心本身的职责就是维护服务实例,它也不需要去检索其他服务
eureka.client.fetch-registry=false
#5.对外提供的注册入口
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
--注意:两个Eureka服务器,是通过主机名和端口来互相发现的。
因此配置Eureka高可用,就是在配置主机名和端口。
主机名(eureka.instance.hostname)服务端口(server.port)
Eureka 1eureka15121
Eureka 2eureka25122
修改第一个Eureka的application.properties文件
#1.配置端口
server.port=5121
#2.配置eureka主机名
eureka.instance.hostname=eureka1
#3.由于我们目前创建的应用是一个服务注册中心,而不是普通的应用,默认情况下,这个应用会向注册中心(也是它自己)注册它自己,设置为false表示禁止这种默认行为
eureka.client.register-with-eureka=false
#4.表示不去检索其他的服务,因为服务注册中心本身的职责就是维护服务实例,它也不需要去检索其他服务
eureka.client.fetch-registry=false
#5.对外提供的注册入口,关联其它的Eureka2
eureka.client.service-url.defaultZone=http://eureka2:5122/eureka/
修改第二个Eureka的application.properties文件
#1.配置端口
server.port=5122
#2.配置eureka主机名
eureka.instance.hostname=eureka2
#3.由于我们目前创建的应用是一个服务注册中心,而不是普通的应用,默认情况下,这个应用会向注册中心(也是它自己)注册它自己,设置为false表示禁止这种默认行为
eureka.client.register-with-eureka=false
#4.表示不去检索其他的服务,因为服务注册中心本身的职责就是维护服务实例,它也不需要去检索其他服务
eureka.client.fetch-registry=false
#5.对外提供的注册入口,关联其它的Eureka2
eureka.client.service-url.defaultZone=http://eureka1:5121/eureka/
修改本地hosts文件,注册Eureka主机名
文件位置:C:\Windows\System32\drivers\etc\hosts。(注意:使用管理员身份编辑)
第四步:分别启动两个Eureka测试
--启动Eureka1成功
--启动Eureka2成功
--访问Eureka1控制台
--访问Eureka2控制台
步骤说明:
(1)修改前面的实例,使用Eureka集群配置。
(2)依次启动前面的实例。
(3)通过instanceClient调用服务。
(4)关闭其中一个Eureka,观察是否任然可以调用成功。
(5)如果任然可用,则Eureka高可用配置成功。
修改实例instanceServer的application.properties文件
#指定实例名
spring.application.name=instanceServer
#指定Eureka服务端访问路径,多个Eureka使用逗号隔开
eureka.client.service-url.defaultZone=http://eureka1:5121/eureka, http://eureka2:5122/eureka
#指定实例端口
server.port=8080
修改实例instanceClient的application.properties文件
#指定实例名
spring.application.name=instanceClient
#指定Eureka服务端访问路径,多个Eureka使用逗号隔开
eureka.client.service-url.defaultZone=http://eureka1:5121/eureka, http://eureka2:5122/eureka
#指定实例端口
server.port=8081
修改实例instanceServer2的application.properties文件
#指定实例名
spring.application.name=instanceServer
#指定Eureka服务端访问路径,多个Eureka使用逗号隔开
eureka.client.service-url.defaultZone=http://eureka1:5121/eureka, http://eureka2:5122/eureka
#指定实例端口
server.port=8082
依次启动这三个实例
--启动实例instanceServer成功
--启动实例instanceClient成功
--启动实例instanceServer2成功
测试实例2调用远程服务
--测试成功。
--关闭Eureka1
--重新访问实例2
--测试成功。高可用配置成功!!!
说明:访问Eureka时,需要指定用户名、密码进行身份认证。
配置步骤说明:(1)在Eureka服务端,开启安全认证
(2)在Eureka客户端,进行身份认证
第一步:添加身份认证依赖
--修改pom.xml文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
--在Eureka服务端,修改application.properties文件,指定用户名、密码
#配置Eureka安全认证
security.basic.enabled=true
security.user.name=root
security.user.password=gzsxt
说明:如果配置了Eureka高可用,Eureka之间相互访问时,需认证身份。
#1.配置端口
server.port=5121
#2.配置eureka主机名
eureka.instance.hostname=eureka1
#3.是否将自身注册为服务 false表示不注册
eureka.client.register-with-eureka=false
#4.是否主动发现服务 false表示不发现
eureka.client.fetch-registry=false
#5.对外提供的注册入口
eureka.client.service-url.defaultZone=http://root:gzsxt@eureka2:5122/eureka/
#配置Eureka安全认证
security.basic.enabled=true
security.user.name=root
security.user.password=gzsxt
--在服务系统中,修改application.properties文件,进行身份认证
#指定Eureka服务端访问路径
eureka.client.service-url.defaultZone=http://root:gzsxt@eureka1:5121/eureka,http://root:gzsxt@eureka2:5122/eureka