继续我的Spring-Cloud学习旅程,早些时候我已经学习了如何创建一个典型的以Spring-Cloud和Netflix OSS为基础的微服务环境 - 在这个具体的列子中两个关键的组件,Eureka用来注册、发现服务和Spring Cloud Configuration用来维护一个服务的配置文件的中央仓库。这里我将会展示我如何开发两个微服务样品,一个简单的“pong”服务和一个调用“pong”服务的“ping”服务。
@RestController public class PongController { @Value("${reply.message}") private String message; @RequestMapping(value = "/message", method = RequestMethod.POST) public Resource<MessageAcknowledgement> pongMessage(@RequestBody Message input) { return new Resource<>( new MessageAcknowledgement(input.getId(), input.getPayload(), message)); } }
它获得了一个消息并且以一个确认应答。这里服务使用了配置服务器提供的"reply.message"属性。但"pong"服务是如何找到配置服务器的呢,有两种方法 - 直接定义配置服务器的位置,或者通过Eureka找到配置服务器。我使用了Eureka来找到配置文件服务器。Spring Cloud使这整个流程非常简单,所有它需要的只是一个包含了下面几行的"bootstrap.yml"属性文件:
--- spring: application: name: sample-pong cloud: config: discovery: enabled: true serviceId: SAMPLE-CONFIG eureka: instance: nonSecurePort: ${server.port:8082} client: serviceUrl: defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/
Eureka的位置定义通过 "eureka.client.serviceUrl"属性和 "spring.cloud.config.discovery.enabled" 设置为 "true" 来明确提出配置服务器将会通过Eureka服务器被发现(发布)。
简单的说,这意味着Eureka和配置服务器在启动其他真正的服务之前必须已经完全启动,他们是预先必需的和在整个架构启动时让其中的组件可用的的基础。
配置服务器拥有"sample-pong"服务需要的属性,它们可以在配置服务器的端点 - http://localhost:8888/sample-pong/default中被验证,8888是服务端点的端口号,和应该以下行的内容响应:
"name": "sample-pong", "profiles": [ "default" ], "label": "master", "propertySources": [ { "name": "classpath:/config/sample-pong.yml", "source": { "reply.message": "Pong" } } ] }
可以看到来自中心的"reply.message"属性将会被pong service使用作为确认的消息。
现在来设置一个端点作为一个服务,作为一个Spring boot为基础的端点所需要的就是下面几行:
@SpringBootApplication @EnableDiscoveryClient public class PongApplication { public static void main(String[] args) { SpringApplication.run(PongApplication.class, args); } }
这些完成了"pong"服务的编码。
现在集中完成一个"pong"微服务的消费者,命名它为"ping"微服务。Spring-Cloud和Netflix OSS提供了许多选项来调用Eureka上注册的服务端点,总结下我拥有的 选项:
1.使用原始的Eureka DiscoveryClient 来找到服务实例的主机并且用Spring的RestTemplate来发起调用。
2.使用Ribbon,一个使用Eureka来找到服务实例的客户端负载均衡解决方案
3. 使用Feigin,它使用了一个说明性的方法来调用服务。它内部使用了Ribbon
我使用了Feign。所有需要的是一个实现了调用服务的协议的接口:
package org.bk.consumer.feign; import org.bk.consumer.domain.Message; import org.bk.consumer.domain.MessageAcknowledgement; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @FeignClient("samplepong") public interface PongClient { @RequestMapping(method = RequestMethod.POST, value = "/message", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @ResponseBody MessageAcknowledgement sendMessage(@RequestBody Message message); }
注解@FeignClient("samplepong") 内部指向一个Ribbon"命名"叫"samplepong"客户端。这意味着在配置文件中肯定有一个以此命名的客户端记录,在我的例子中我把这些记录定义在application.yml文件中:
samplepong: ribbon: DeploymentContextBasedVipAddresses: sample-pong NIWSServerListClassName: com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList ReadTimeout: 5000 MaxAutoRetries: 2
这里最重要的记录是"samplepong.ribbon.DeploymentContextBasedVipAddresses"指向被Ribbon调用时发现的"pong"服务实例的Eureka 注册地址
剩下的应用是路由Spring Boot引用。我已经在Hystrix后面暴露了服务调用地址,Hystrix会给调用失败加上防护和从底层上保护了FeignClient:.
package org.bk.consumer.service; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.bk.consumer.domain.Message; import org.bk.consumer.domain.MessageAcknowledgement; import org.bk.consumer.feign.PongClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Service("hystrixPongClient") public class HystrixWrappedPongClient implements PongClient { @Autowired @Qualifier("pongClient") private PongClient feignPongClient; @Override @HystrixCommand(fallbackMethod = "fallBackCall") public MessageAcknowledgement sendMessage(Message message) { return this.feignPongClient.sendMessage(message); } public MessageAcknowledgement fallBackCall(Message message) { MessageAcknowledgement fallback = new MessageAcknowledgement(message.getId(), message.getPayload(), "FAILED SERVICE CALL! - FALLING BACK"); return fallback; } }
。。。
对spring cloud的知识点都已经在上面的内容里,所以后面的启动过程就不继续翻译了
2. Most of the code is heavily borrowed from the spring-cloud-samples repository - https://github.com/spring-cloud-samples
原文:https://dzone.com/articles/learning-spring-cloud-writing