前面两天介绍了SpringCloud的基础知识,以及窥探了一下加载流程,整个代码还是很长并且晦涩的,一定要多debug去跟进,看每个对象何时创建和赋值,一步步跟着走,这样才能对整个流程有一个很好的了解。这也是我们去阅读所有的开源框架和组件的源码的方法。
今天,我们开始研读SpringCloud集成的组件,结合代码和实际项目中的用途,来了解SpringCloud为何可以实现分布式的服务架构。就像前面所说,其实SprngCloud并不是一个新的服务框架,他只是集成了SpringBoot和一些开源的针对微服务,分布式有成熟的解决方案的一些开源的框架。而我们要关注的,就是它集成的那些优秀的框架,以及用途和我们在项目中如何应用。说到SpringCloud集成的框架,就不得不说SpringCloud分布式开发五大神兽,分别是 Eureka,Netflix Ribbon,Netflix Hystrix,Netflix Zuul,Spring Cloud Config,今天,我们先来了解一下Eureka相关知识以及应用。
什么是Eureka?
Eureka是Netflix开发的服务发现框架,比较类似于阿里的Dubbo。Eureka它是一个基于restful的服务,它本身是一个成熟的实现负载均衡和中间层服务故障转移的中间层服务。而SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server和Eureka Clien。
上面就是SpringCloud集成Eureka的jar包目录。顾名思义,Eureka Server是用来提供服务注册服务的,而Eureka Client则是将自己服务注册到Eureke Server上供其他服务进行服务用的。
Eureka是怎么实现服务治理的
想必大家应该都接触或者了解过Dubbo和zookeeper,zookeeper是一个文件管理系统,dubbo会将生产者的服务信息注册到zookeeper的节点上,而zookeeper会监听对他节点感兴趣的消费者,当节点发生变化的时候,会通知到消费者。而Eureka和这个很类似,不过SpringCloud集成Eureka,本着一切从简(简化配置,约定大于配置的原则),对Eureka的配置进行了简化,这个下面会详细讲解。Eureka是有两个组件,一个是Eureka Server,服务端,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。另一个是Eureka Client,客户端启动的时候,会把自己提供的服务信息提供给Eureka Server,包括服务的主机与端口号、服务版本号、通讯协议等一些附加信息,同时,Eureka Client还要每隔一段时间向Eureka Server发送心跳检测,默认是30s,可以自行配置,如果过了这个时间服务端没有收到心跳检测,默认服务挂了,会把他从维护的注册中心中清除掉。同时,client从server拉取到服务信息后,本地也会缓存一份,这个时候如果Eureka Server出了故障,也不会影响调用服务。client可配置多长时间去Eureka Server拉取一次最新的订阅的服务信息。
总结一下,其实就是Eureka Client启动时,向Eureka Server提供自己的服务信息,其他服务订阅你的服务的时候,Eureka Server会返回服务信息,主要是ip和接口,然后消费者再做HTTP请求调用远程服务的接口。
Eureka常用配置
#客户端
eureka:
instance:
#eureka客户端需要多长时间发送心跳给eureka服务器,表明他仍然或者,默认30秒
lease-renewal-interval-in-seconds: 5
#eureka服务器在接受到客户端的最后一次发出的心跳后,需要等待多久才可以将此客户端删除
lease-expiration-duration-in-seconds: 10
#prefer-ip-address为true时以IP地址注册到服务中心,相互注册使用IP地址
#ip-address: 192.168.1.1 #强制指定IP地址,默认会获取本机的IP地址
prefer-ip-address: false
#服务地址,ip和接口
instance-id: ${spring.cloud.client.hostname}:${server.port}(${game.server_id})
client:
#表示eureka client间隔多久去拉取服务器注册信息,默认为30秒
registry-fetch-interval-seconds: 30
#表示eureka client间隔多久去拉取服务器注册信息,默认为30秒
registry-fetch-interval-seconds: 30registry-fetch-interval-seconds: 30
serviceUrl:
#Eureka Server地址。格式为http://账号:密码@ip:port/eureka
defaultZone: ${ss.eurl}
#是否向服务注册中心注册自己
register-with-eureka: false
#Eureka服务端
eureka:
instance:
#服务注册中心实例的主机名
hostname: localhost
client:
#是否向服务注册中心注册自己
register-with-eureka: false
#是否检索服务
fetch-registry: false
service-url:
#服务注册中心的配置内容,指定服务注册中心的位置
defaultZone: http://user:password@${eureka.instance.hostname}:8761/eureka
基本上,Eureka Server和Eureka Client会用到的配置内容就上面这些。如果有特殊需求,可以去看Spring Cloud的官方配置。
Eureka服务端开发
pom文件
<?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>
<groupId>com.eureka.server</groupId>
<artifactId>eureka-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</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>
</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>
这里注意,引入的Eureka依赖一定要是spring-cloud-starter-netflix-eureka-server。其他的都是Spring Cloud的依赖和Spring Boot的引入的一些常用的依赖。
启动类编码
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
这里两个注解,@SpringBootApplication是Sping Boot的启动类,主要标注这是SpringBoot的没动类,并且加载Factory机制和开启bean扫描。@EnableEurekaServer则是表示这是一个Eureka Server服务,并开启Server服务,启动注册中心。
启动服务,访问http://localhost:8761/,ip是主机id,端口是上面提到的yml文件配置的server.port,出现如下图,表示启动成功:
Eureka客户端
pom文件
这里和Eureka Server服务端基本类似,就是之前标注的关于Eureka的引入要换成客户端的
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>1.4.4.RELEASE</version>
</dependency>
启动类编码
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(EurekaClientApplication.class);
application.run(args);
}
}
#yml文件
server:
port: 8081
spring:
application:
name: myCloudSample
eureka:
client:
service-url:
defaultZone: http://user:password@localhost:8761/eureka
这里的Eureka Server的地址要写服务端的service.url.然后这个是可以被发现,也是可以注册的,所以都用默认即可。这里最重要的两个注解,一个是@EnableFeignClients,表示这个服务是可以被发现,通过Feign远程调用的,@EnableDiscoveryClient注解,则是表示这是一个可以被发现的Eureka客户端。
然后启动客户端,打印注册成功的信息:
查看我们的Eureka Server上的信息,发现Application多了一个注册的服务:
注册的服务的名称就是我们定义的Eureka Server的应用名称,ip和端口以及主机都是我们的,至此,客户端也搞定了。
测试服务的远程调用
首先,我们在Eureka Client上定义一个接口,就暂且定义为HelloController,如下:
@RestController
public class helloController {
@RequestMapping(value = "/hello")
@ResponseBody
public String sayHello(){
System.out.println("=========");
return "Hello word";
}
}
然后,写一个消费者的服务,远程调用Eureka Client的这个/hello的接口,首先,创建一个Eureka的服务,消费者其实也是一个客户端,所以通Eureka Client:
#启动类
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class CloudHelloApplication {
public static void main(String[] args) {
SpringApplication.run(CloudHelloApplication.class, args);
}
}
#yml
server:
port: 8082
spring:
application:
name: helloSample
profiles:
active: dev,file,console
cloud:
config:
server:
git:
uri: ?
username:?
password: ?
eureka:
client:
service-url:
defaultZone: http://user:password@localhost:8761/eureka
然后写远程调用myCloudSample的方法,Eureka服务之间互相调用方法都是通用的,先上一个示例代码:
@Component
@FeignClient(value = "myCloudSample")
public interface ClientCenter {
@RequestMapping(value = "/hello", produces= "application/json", method = RequestMethod.POST)
@ResponseBody
String sayHello();
}
@FeignClient表示调用的远程服务的应用名,即spring.application.name:中定义的,我们这里是myCloudSample,@RequestMapping是表示对应服务下面的哪个接口,里面的参数value表示url,produces表示返回类型,consumes则表示入参类型,method表示调用方式,即http请求的方式。@ResponseBody就是调用的返回为字符串。
接口有了,接下来就是测试类了
@RestController
public class HelloController {
@Autowired
private ClientCenter clientCenter;
@RequestMapping(value = "/hello")
@ResponseBody
public String sayHello(){
return clientCenter.sayHello();
}
}
我们启动这个测试的服务,会发现Eureka Server中的应用Applicaiton又多了一个,正是我们这个测试的服务,这里就不截图了。然后访问测试类的hello的接口,http://localhost:8082/hello, 打印出我们的hello word,表示调用成功:
是不是很方便,很easy,大大简化了我们的代码量,不用在代码中去做一次次的http请求和处理。
ok,Eureka的学习基本就到这里了,没使用过的小伙伴一定记得自己动手敲一遍,很多东西可能看着简单,但是,抛开一切,自己从头来敲,总会发现各种各样的问题,这个也是我们学习和进步的最好的方式。