一、简介
在上一篇中,我们介绍注册中心 Eureka, 但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和 Feign 一起讲比较好,因为在实际项目中,都是使用声明式调用服务。而不会在客服端和服务端存储 2 份相同的 model 和 api 定义。Feign 在 RestTemplate 的基础上对其封装,由它来帮助我们定义和实现依赖服务接口的定义。Spring Cloud Feign 基于 Netflix Feign 实现的,整理 Spring Cloud Ribbon 与 Spring Cloud Hystrix,并且实现了声明式的 web 服务客户端定义方式。
二、实践
在上一节中,我继续添加工程模块,最后的模块如下:
首先我们需要建一个工程,名为 hello-service-api 在工程主要定义对外提供的 model 和 api。服务的提供方和服务的消费方都要依赖该工程 jar,这样我们就可以只维护一份 model 和 api 定义。在该例子中主要如下结构
非常简单,只有 1 个 HelloServieRemoteApi 接口定义和 User 对象。
- @RequestMapping("/hello-service-remote")
- public interface HelloServiceRemoteApi {
- @RequestMapping(value = "/hello1", method = RequestMethod.GET)
- String hello(@RequestParam("name") String name);
- @RequestMapping(value = "/hello2", method = RequestMethod.GET)
- User hello(@RequestHeader("name") String name,@RequestHeader("age") Integer age);
- @RequestMapping(value = "/hello3", method = RequestMethod.POST)
- String hello(@RequestBody User user);
- }
在上面的接口定义中,我们非常的清晰,在接口上面我们主映射为 / hello-service-remote,个人感觉已接口的名字通过 "-" 这样可以非常的区分不同的接口路径,防止多接口时发生重复。接下来具体方法的上面可以定义于方法名一样的路径映射,我这里已 /hello1,/hello2,/hello3 为主。
- public class User implements Serializable {
- private static final long serialVersionUID = -7233238826463139634L;
- private Long id;
- private String name;
- private Integer age;
- public User() {
- }
- public User(String name, Integer age) {
- this.name = name;
- this.age = age;
- }
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- @Override
- public String toString() {
- return "User{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
上面就是简单的一个 User 对象。
从上面的接口中发现,该 api 工程需要引入 spring-web 包。所以它的 pom.xml 如下:
- <?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>
- <artifactId>hello-service-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- <groupId>com.qee.hello</groupId>
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>4.2.9.RELEASE</version>
- </dependency>
- </dependencies>
- </project>
从上面的 pom.xml 定义中,我们知道 hello-service-api 并不集成父工程 micro-service-integration。一般作为 api 提供的工程 jar, 依赖越少越好。
接下来我们需要创建一个提供者工程,我们把它命名为 hello-service-compose。该工程也是标准的 Spring Boot 工程。具体的目录如下:
在工程中我们有一个刚才 hello-service-api 接口定义的实现。代码如下:
- @RestController
- public class HelloServiceRemoteApiImpl implements HelloServiceRemoteApi {
- @Override
- public String hello(@RequestParam("name") String name) {
- return "hello " + name;
- }
- @Override
- public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
- try {
- name= URLDecoder.decode(name,"UTF-8");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- return new User(name, age);
- }
- @Override
- public String hello(@RequestBody User user) {
- if (user == null) {
- return "未知";
- }
- return user.toString();
- }
- }
因为是测试工程,所以它没有复杂的业务逻辑。接下来就是 HelloProviderApplication 的启动 main.
- package com.qee.remote;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
- @EnableDiscoveryClient
- @SpringBootApplication
- public class HelloProviderApplication {
- public static void main(String[] args) {
- SpringApplication.run(HelloProviderApplication.class, args);
- }
- }
在上面有 2 个注解,第一个 SpringBootApplication 就是 Spring Boot 启动注解,EnableDiscoveryClient 该注解会把 RestController 修饰的类注册到注册中心去。
接下来我们来看下 application.properties
- server.port=8885
- spring.application.name=hello-service-compose
- eureka.instance.hostname=register.center.com
- eureka.instance.server.port=8881
- #默认的注册域
- eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/
- #控制台彩色输出
- spring.output.ansi.enabled=ALWAYS
从上面信息我们知道,改工程启动端口为 8885,注册中心地址为 register.center.com:8881。
接下来我们查看一下该工程的 pom.xml 定义
- <?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">
- <parent>
- <artifactId>micro-service-integration</artifactId>
- <groupId>spring.cloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>hello-service-compose</artifactId>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>com.qee.hello</groupId>
- <artifactId>hello-service-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-ribbon</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- </dependencies>
- </project>
从 pom.xml 文件中知道该工程依赖了 web,euraka,ribbon,actuator,hello-service-api 包。其中 euraka 为服务注册和发现包,ribbon 为服务调用负载均衡包,actuator 为工程元信息检测包。还有我们自己定义的 hello-service-api 包。
在上面的简单配置和编写后,我们就可以启动工程把该 HelloServiceRemoteApi 注册到注册中心去了。
现在有了服务接口定义包和服务提供工程,现在我们编写一下服务调用工程。命名为 hello-service-web。该工程的目录结构如下:
首先我们来看下 HelloBackgroundService 这个接口。
- @FeignClient(value = "hello-service-compose")
- public interface HelloBackgroundService extends HelloServiceRemoteApi{
- }
非常的简单,主要继承我们之前编辑的 HelloServiceRemoteApi, 并且在上面打上 FeignClient 注解,该注解指定服务名来绑定服务。该注解同时会使服务调用具有负载均衡的能力。
接下来我们来看下 HelloController 类
- @RestController
- public class HelloController {
- @Autowired
- private HelloBackgroundService helloBackgroundService;
- @RequestMapping("/hello")
- public Map<String,Object> hello(){
- Map<String,Object> ret = new HashMap<String, Object>();
- StringBuffer sb = new StringBuffer();
- String s1 = helloBackgroundService.hello("张三");
- sb.append(s1).append("\n");
- User user = null;
- try {
- user = helloBackgroundService.hello(URLEncoder.encode("李四", "UTF-8"), 30);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- sb.append(user.toString()).append("\n");
- String s3 = helloBackgroundService.hello(new User("王五", 19));
- sb.append(s3).append("\n");
- ret.put("show",sb.toString());
- return ret;
- }
- }
从上面得知我们,我们就可以调用之前的我们编写的 HelloBackgroundService 了。接下来我们查看一下启动类 HelloConsumerApp
- package com.qee;
- import feign.Logger;
- 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;
- import org.springframework.context.annotation.Bean;
- @EnableFeignClients
- @EnableDiscoveryClient
- @SpringBootApplication
- public class HelloConsumerApp {
- @Bean
- Logger.Level feginLoggerLevel(){
- return Logger.Level.FULL;
- }
- public static void main(String[] args) {
- SpringApplication.run(HelloConsumerApp.class, args);
- }
- }
在该启动了中又多了一个注解 EnableFeignClients ,该注解开启 Spring Cloud Feign 的支持。接着我们来查看一下 application.properties
- server.port=8887
- spring.application.name=hello-service-web
- eureka.instance.hostname=register.center.com
- eureka.instance.server.port=8881
- #默认的注册域
- eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/
- #开启请求压缩功能
- feign.compression.request.enabled=true
- #开启响应压缩功能
- feign.compression.response.enabled=true
- #指定压缩请求数据类型
- feign.compression.request.mime-types=text/xml;application/xml;application/json
- #如果传输超过该字节,就对其进行压缩
- feign.compression.request.min-request-size=2048
- #控制台彩色输出
- spring.output.ansi.enabled=ALWAYS
- #日志配置,该接口的日志级别
- logging.level.com.qee.service.HelloBackgroundService=DEBUG
从上面的注释中,我们已经可以知道具体的配置参数的作用,这里就不详细介绍了。从上面的配置和编写我们可以知道,该工程需要如下的依赖包,pom.xml 文件如下
- <?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">
- <parent>
- <artifactId>micro-service-integration</artifactId>
- <groupId>spring.cloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>hello-service-web</artifactId>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>com.qee.hello</groupId>
- <artifactId>hello-service-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-ribbon</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-feign</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- </dependencies>
- </project>
该服务消费端,比服务提供方多了一个 jar 依赖,就是 feign。该 jar 的作用就是提供声明式的服务调用。到这里我们本章的内容大致结束,最后我们来运行这几个工程。查看如下结果:
从上面我们可以看到 2 个工程 hello-service-compose 和 hello-service-web 都已经注册到注册中心 eureka 上了。接下来看一下调用结果:
到这里服务注册中心启动,服务注册,服务消费大致都已完成,之后会向大家一起学习服务调用的负载均衡 Ribbon 和服务容错保护 Hystrix.
来源: http://www.cnblogs.com/liferecord/p/6891188.html