我的上一篇博客已经介绍过了 Eureka 的服务注册中心功能如何使用,在本文,我将搭建一个小程序,来实现服务端注册服务而客户端调用服务的案例。
1 Eureka 基本架构的三种角色
- 服务注册中心:用于提供服务注册和发现
- 服务提供者:将自身服务注册到 Eureka 中,令服务消费者调用
- 服务消费者:从 Eureka 获得注册服务列表,以便消费服务
我上篇文章已介绍过服务注册中心的实现,本文章我将重点介绍服务提供者和服务消费者的实现。
2 服务提供者的构建
我们新建一个项目,并命名为 EurekaProducer 。
2.1 引入依赖
<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</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
2.2 application.properties
spring.application.name=producer
server.port=8080
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
2.3 启动类
我们需要在启动类上添加 @EnableDiscoveryClient 注解,该注解用于启动服务的注册与发现。
package com.example.EurekaProducer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaProducerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaProducerApplication.class, args);
}
}
2.4 控制器
package com.example.EurekaProducer.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
@ResponseBody
public String helloWorld(int id,String saying) {
return "序号为" + id + "的用户发布了一条新消息:" + saying;
}
}
2.5 测试
启动 Eureka,EurekaProducer 两个项目,然后打开 Eureka 界面
我们可以发现该服务已注册到 Eureka 。
然后我们在浏览器输入 http://localhost:8080/helloWorld?id=2&saying=%E7%89%9B%E9%80%BC,发现服务正常。
3 服务消费者的构建
我们新建一个项目,并命名为 EurekaConsumer 。
3.1 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
这里注意,除了 Eureka 的配置之外,我们还需要引入 Feign 的配置。Feign 是一个声明式 Web Service 客户端,用于远程调用。关于更多的 Feign 知识,我们会在下一篇博客介绍。
3.2 application.properties
spring.application.name=consumer
server.port=8082
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
3.3 启动类
package com.example.EurekaConsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
我们需要在启动类上添加 @EnableDiscoveryClient,@EnableFeignClients 两个注解,其中 @EnableFeignClients 用于启用 feign 进行远程调用。
3.4 启动 feign 调用
package com.example.EurekaConsumer.Service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Component
@FeignClient(name= "producer")//name为远程服务名,即远程服务spring.application.name设置的名字
public interface HelloWorldService {
//调用方法需要与远程服务中的方法名和参数一致
@RequestMapping("/helloWorld")
public String helloWorld(@RequestParam(value = "id")int id,@RequestParam(value = "saying")String saying);
}
注意点已经在注解中标出。
3.5 控制层调用远程服务
package com.example.EurekaConsumer.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.EurekaConsumer.Service.HelloWorldService;
@Controller
public class HelloWorldController {
@Autowired
HelloWorldService helloWorldService;
@ResponseBody
@RequestMapping("/helloWorld")
public String use(int id,String saying) {
return helloWorldService.helloWorld(id, saying);
}
}
就像调用普通方法一样即可。至此,我们的服务注册与调用例子已经实现完毕。
3.6 测试
启动 Eureka,EurekaProducer,EurekaConsumer 三个项目,然后打开 Eureka 界面
两个服务均已注册到 Eureka。我们首先在浏览器输入 http://localhost:8080/helloWorld?id=3&saying=%E7%89%9B%E9%80%BC,发现 EurekaProducer 提供的服务正常。
然后我们输入 http://localhost:8082/helloWorld?id=4&saying=%E7%89%9B%E9%80%BC,发现 EurekaConsumer 已经成功通过 feign 调用了远程服务。至此,我们的测试结束。
4 对 Eureka 使用的总结
- Eureka 客户端会每隔30秒会发送一次心跳续约,通过续约来告知 Eureka Server 该客户端仍然存在,即服务续约。
- Eureka 客户端会从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息每30秒钟更新一次。每次返回注册列表信息可能与 Eureka 客户端的缓存信息不同, Eureka客户端会进行自动处理。如果注册列表信息不能及时匹配,Eureka客户端则会重新获取整个注册表信息。
- Eureka 客户端在程序关闭时会向 Eureka 服务器发送取消请求。发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:
DiscoveryManager.getInstance().shutdownComponent(),即服务下线。 - 默认情况下,如果 Eureka 客户端连续90秒没有向 Eureka 服务器发送服务续约,Eureka
服务器会将该服务实例从服务注册列表删除,即服务剔除。