在Spring Cloud中,开发Eureka Client组件还是非常方便的。
一、服务注册(服务提供者)
pom依赖:
<dependencies> <!-- eureka client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- actuator监控信息 actuator 组件是Spring Boot的监控组件,actuator一旦应用,在启动的时候,会发布一系列的URL服务。包含一个shutdown服务,代表优雅关闭。 当Spring Boot 应用中的actuator组件接收到shutdown请求的时候,会触发优雅关闭。 如果当前应用中有Eureka Client的集成,则会触发Eureka Client向Eureka Server发起一个shutdown优雅停服的请求--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <finalName>microservicecloud</finalName> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering><!--开启过滤--> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <delimiters> <delimit>$</delimit><!---解析以$开始和$结尾且在src/main/resources目录下的配置信息--> </delimiters> </configuration> </plugin> </plugins> </build>
全局配置:
在配置Eureka Server信息时,建议将Eureka Server集群中的所有节点依次配置,Eureka Client在注册服务的时候,会根据节点列表依次访问Eureka Server集群节点,只要注册成功,后续Eureka Server节点不再访问注册。虽然Eureka Server集群各节点可以相互发现服务,但是Eureka Server集群中每个节点对服务的管理都使用连带责任,及从某Eureka Server节点发现服务A,如果这个Eureka Server节点宕机,则A服务同时从服务列表中删除。
# 定义SpringBoot应用的名称,建议必须提供。在SpringCloud中,对服务的最大粒度的管理是使用应用命名的 # 最好是一个应用一个名称,在Consumer角色开发的时候,比较容易查找Provider spring.application.name=appService-name server.port=8888 #eureka微服务实例名称修改,不采用默认的, 默认是spring.application.name的大写 eureka.instance.instance-id=appService-minsoft # 配置Eureka Server的地址信息,如果是Eureka Server集群,多个节点使用逗号','分割。 # 如果开启了安全认证,使用HTTP Bacic格式提供用户名和密码。 # 如果Eureka Server是一个集群,那么配置Eureka Server节点信息的时候,建议将所有的Eureka Server节点信息都配置上 # 实际上,只配置一个Eureka Server节点其实就可以了,但是,Eureka Server对服务的管理有连带责任。如果只配置一个Eureka Server节点,那么会导致级联删除的风险,可能导致服务不可靠 # 如果配置了多个Eureka Server节点,Eureka不会将当期的服务同时注册到所有Eureka Server节点上 # 从第一个配置的Eureka Server节点开始注册,如果注册成功,后续的Eureka Server节点不再重复注册 # 每30秒,Eureka Client发送一个心跳到Eureka Server上,如果心跳没有反馈,则从已配置的Eureka Server节点列表的下一个服务节点继续注册。 # 这样做可以保证服务的可靠性,降低服务连带责任导致的服务不可靠。 # 如果多个Eureka Client需要注册,建议Eureka Server的服务列表顺序是随机排列的。 # 如:有Eureka Server s1,s2,s3,有Eureka Client c1,c2,c3。 # 那么在c1上配置的Eureka Server列表建议是s1,s2,s3,在c2上配置的是s2,s3,s1,在c3上配置的是s3,s1,s2,这样可以更好的利用Eureka Server集群的特性。 # 因为Eureka Server和Eureka Client对心跳的监测都是3*间隔时间的,所以会有服务列表数据的不同步可能。 # 所以在CAP原则上,Eureka Server是保证AP原则,放弃C原则的。 # 注意:多个地址之间不要有多余的空格, 只有一个逗号 eureka.client.serviceUrl.defaultZone=http://admin:1234@eurekaserver1:8761/eureka/,http://admin:1234@eurekaserver2:8761/eureka/ #启动所有端点, 也可以设置部分启动, 如:env,beans。默认是health, info management.endpoints.web.exposure.include=* ## 启用shutdown,优雅停服功能,配置actuator的优雅关闭 ## actuator 组件监听shutdown请求地址的时候,要求请求的method必须是POST ## shutdown的请求地址是使用:@PostMapping或@RequestMapping(method=RequestMethod.POST) management.endpoint.shutdown.enabled=true #访问信息可以使用IP地址 eureka.instance.prefer-ip-address=true # 对该微服务进行简单的信息介绍, 随便配置 info.app.name=appService-name info.company.name=myApplication info.build.artifactId=$project.artifactId$ info.build.version=$project.version$
建议:如果有多个服务功能需要注册,那么在设置Eureka Server信息的时候,推荐异序排列。如:现在有3个工程A、B、C需要注册服务到Eureka Server集群中,集群节点有三个,分别是e1、e2、e3,那么在工程中推荐配置为,A工程配置-e1,e2,e3,B工程配置e2,e3,e1,C工程配置e3,e1,e2。这样可以更好的利用Eureka Server集群的特性。
这里使用的是8888端口,需要在防火墙打开。
启动类:
需要在启动类上新增注解@EnableEurekaClient,代表当前应用开启Eureka客户端,应用启动后,会自动将服务注册到Eureka Server中。
@EnableEurekaClient和@EnableDiscoveryClient的区别?@EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现;而@EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient @SpringBootApplication public class AppService { public static void main(String[] args) { SpringApplication.run(AppService.class, args); } }
对外接口:
@Controller public class TestApplicationServiceController { @RequestMapping("/test") @ResponseBody public List<Map<String, Object>> test(){ List<Map<String, Object>> result = new ArrayList<>(); for(int i = 0; i < 3; i++){ Map<String, Object> data = new HashMap<>(); data.put("id", i+1); data.put("name", "test name " + i); data.put("age", 20+i); result.add(data); } return result; } }
二、服务发现(服务消费者)
在Spring Cloud中,服务消费方代码的开发确实比较麻烦,并不像Dubbo那么直接注入服务接口代理对象,通过代理对象方法直接访问远程服务。在Spring Cloud中,微服务的提供是通过REST风格提供的,也就是服务的调用是基于HTTP协议的,所以在服务调用上比较麻烦。
pom依赖:
同服务提供者。
全局配置:
在Eureka Server中,对服务的管理是基于spring应用名称的,所以不同的服务推荐使用不同的应用名称。
# 定义SpringBoot应用的名称,建议必须提供。 spring.application.name=app-client server.port=8111 # 任何Eureka Client都必须注册。如果没有配置Eureka Server节点列表,则注册失败。Eureka client无法正常启动。 # 注意:多个地址之间不要有多余的空格, 只有一个逗号 eureka.client.serviceUrl.defaultZone=http://admin:1234@192.168.178.5:8761/eureka/,http://admin:1234@192.168.178.6:8761/eureka/ # 设置负载均衡策略 appservice-name为调用的服务的名称 # 没有配置全部服务的负载均衡策略的方式。因为不是每个服务都可以使用相同负载均衡策略的。 # 如:搜索服务和注册服务就不能使用相同的负载均衡策略。 appservice-name.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule # 配置服务列表,其中appservice-name代表要访问的服务的应用名,如果有多个服务结点组成集群,多个节点的配置信息使用逗号','分隔。 # 配置服务列表,需要配置要调用的服务的名字和服务所在的位置。 # 服务的名字,就是Application Service(服务提供者)中配置的spring.application.name。 # 服务的位置,就是服务的所在ip和端口。 # 如果服务位置有多个,也就是服务集群,那么使用逗号','分割多个服务列表信息。 appservice-name.ribbon.listOfServers=192.168.178.5:8888
启动类:
@EnableDiscoveryClient @SpringBootApplication public class AppClient { public static void main(String[] args) { SpringApplication.run(AppClient.class, args); } }
请求调用类(并不是只有这一种方式):
/** * 在这里开发Eureka Client中的Application Client角色。就是consumer服务的消费者。 * 服务消费者需要在注册中心中发现服务列表的。且同时将自己注册到注册中心的服务列表中。(参考如下截图) * * consumer在消费provider的时候,是通过LoadBalancer来实现的。 * LoadBalancer简介 : 是Eureka client内置的一个负载均衡器。复杂在发现的服务列表中选择服务应用,获取服务的IP和端口。 * 实现服务的远程调用。 * * application client代码开发相比较dubbo的consumer开发麻烦很多。 * */ @RestController public class TestApplicationClientController { /** * ribbon负载均衡器,其中记录了从Eureka Server中获取的所有服务信息。 * 这些服务的信息是IP和端口等。应用名称,域名,主机名等信息。 */ @Autowired private LoadBalancerClient loadBalancerClient; /** * 通过HTTP协议,发起远程服务调用,实现一个远程的服务消费。 * @return */ @GetMapping public List<Map<String, Object>> test() { // 通过spring应用命名,获取服务实例ServiceInstance对象 // ServiceInstance 封装了服务的基本信息,如 IP,端口 /* * 在Eureka中,对所有注册到Eureka Server中的服务都称为一个service instance服务实例。 * 一个服务实例,就是一个有效的,可用的,provider单体实例或集群实例。 * 每个service instance都和spring application name对应。 * 可以通过spring application name查询service instance */ ServiceInstance si = this.loadBalancerClient.choose("appservice-name"); // 拼接访问服务的URL StringBuilder sb = new StringBuilder(); // http://192.168.178.6:8761/test sb.append("http://").append(si.getHost()) .append(":").append(si.getPort()).append("/test"); System.out.println("本次访问的service是: " + sb.toString()); // SpringMVC RestTemplate,用于快速发起REST请求的模板对象。 /* * RestTemplate是SpringMVC提供的一个用于发起REST请求的模板对象。 * 基于HTTP协议发起请求的。 * 发起请求的方式是exchange。需要的参数是: URL, 请求方式, 请求头, 响应类型,【URL rest参数】。 */ RestTemplate rt = new RestTemplate(); /* * 创建一个响应类型模板。 * 就是REST请求的响应体中的数据类型。 * ParameterizedTypeReference - 代表REST请求的响应体中的数据类型。 */ ParameterizedTypeReference<List<Map<String, Object>>> type = new ParameterizedTypeReference<List<Map<String, Object>>>() { }; /* * ResponseEntity:封装了返回值信息,相当于是HTTP Response中的响应体。 * 发起REST请求。 */ ResponseEntity<List<Map<String, Object>>> response = rt.exchange(sb.toString(), HttpMethod.GET, null, type); /* * ResponseEntity.getBody() - 就是获取响应体中的java对象或返回数据结果。 */ List<Map<String, Object>> result = response.getBody(); return result; } }
LoadBanlancerClient中包含了所有的服务注册信息。
三、优雅关闭服务(优雅停服)
在Spring Cloud中,可以通过HTTP请求的方式,通知Eureka Client优雅停服,这个请求一旦发送到Eureka Client,那么Eureka Client会发送一个shutdown请求到Eureka Server,Eureka Server接收到这个shutdown请求后,会在服务列表中标记这个服务的状态为down,同时Eureka Client应用自动关闭。这个过程就是优雅停服。
如果使用了优雅停服,则不需要再关闭Eureka Server的服务保护模式。
POM依赖:优雅停服是通过Eureka Client发起的,所以需要在Eureka Client中增加新的依赖,这个依赖是autuator组件,添加下述依赖即可。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
修改全局配置文件:Eureka Client默认不开启优雅停服功能,需要在全局配置文件中新增如下内容:
#启动所有端点, 也可以设置部分启动, 如:env,beans。默认是health, info management.endpoints.web.exposure.include=* # 启用shutdown,优雅停服功能 management.endpoint.shutdown.enabled=true
发起shutdown请求:
必须通过POST请求向Eureka Client发起一个shutdown请求。请求路径为:http://ip:port/actuator/shutdown。可以通过任意技术实现,如:HTTPClient、form表单,AJAX等。
建议使用优雅停服方式来关闭Application Service/Application Client服务。