Holy Null 's Blog
Holy Null!
Toggle navigation
Holy Null 's Blog
主页
机器学习
Flume
Nginx
Hadoop
Apache Shiro
架构理论
Docker
Spring Cloud
关于我
归档
标签
Spring Cloud 教程|第四篇 Feign客户端
2017-12-25 15:49:23
557
0
0
holynull
# 第四篇 Feign客户端 上一篇我们介绍了如何使用Spring Cloud开发一个服务,并在Docker环境中进行部署。Spring Cloud中的服务为了保证高可用性,会将服务部署成一个由多个实例组成的集群。通过Feign Client来消费服务,就能够在服务调用时实现负载均衡。 通常服务在应用平台中不是独立存在的,服务之间会存在调用关系。服务之间在互相调用过程中,被调用的服务出现故障导致访问阻塞,会导致整个应用平台雪崩式的崩溃。为了避免这种情况,在服务消费者一端我们使用Hystrix的熔断机制,对长时间没有响应的调用进行断路处理。 ## 一、改造服务提供者 为了验证Feign Client的负载均衡,我们将在`eurekaClient`项目中暴露一个服务端点`/hi`。访问这个端点,将返回实例所在的主机名称。在`com.ultimatech.eurekaclient.ServiceHiApp`中,增加如下代码: ``` @RequestMapping("/hi") public String home(@RequestParam String name) { return "hi " + name + ",i am from :" + hostname + ":" + port; } ``` 上一篇中我们在Docker环境中部署了一个`eurekaClient`的实例,下面我们再部署第二个实例。首先,在`cloud-config`的`resources`目录下创建第二个实例的配置文件`eclient-2-prd.yml`,并`git push`到git服务器上。 ``` eureka: instance: hostname: eclient-2 serviceUrl: defaultZone: http://eureka-1:8761/eureka/,http://eureka-2:8761/eureka/ spring: datasource: # url: jdbc:oracle:thin:@oracle12c:1521:xe url: jdbc:oracle:thin:@10.177.193.116:1521:workflow username: workflow # password: workflow password: workflow1 driver-class-name: oracle.jdbc.OracleDriver max-idle: 10 max-wait: 10000 min-idle: 5 initial-size: 5 #=====================jpa config================================ #实体类维护数据库表结构的具体行为:update/create/create-drop/validate/none jpa: hibernate: ddl-auto: update #打印sql语句 show-sql: true #格式化输出的json字符串 jackson: serialization: indent_output: true ``` 与第一个实例的配置文件不同的地方仅如下关于`hostname`的配置: ``` eureka: instance: hostname: eclient-2 ``` 当Feign Client负载到eclient-1时,`/hi?name=aaa`端点会返回: ``` hi aaa,i am from : eclient-1:8080 ``` 当Feign Client负载到eclient-2时,`/hi?name=aaa`端点会返回: ``` hi aaa,i am from : eclient-2:8080 ``` 在`eurekaClient/config`目录下,为新的实例创建一个Docker环境下启动配置文件`eclient-2-bootstrap.yml`: ``` spring: cloud: config: name: eclient-2 label: master profile: prd eureka: client: serviceUrl: defaultZone: http://eureka-1:8761/eureka/,http://eureka-2:8761/eureka/ ``` ## 二、部署第二个服务提供者实例 在`spring-cloud-poc`目录下的`docker-compose.yml`中的`services`添加第二个实例: ``` eclient-2: build: ./docker/webnode container_name: eclient-2 volumes: - "/tmp" - "./eurekaClient/target/eurekaClient-1.0-SNAPSHOT.jar:/app.jar" - "/config" - "./eurekaClient/config/eclient-2-bootstrap.yml:/config/bootstrap-prd.yml" depends_on: - eureka-1 - eureka-2 - config-server-1 environment: HOSTNAME: eclient-2 JAVA_OPTS: -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m networks: mynet: ipv4_address: 172.19.0.6 extra_hosts: - "eureka-1:172.19.0.2" - "eureka-2:172.19.0.3" - "eclient-1:172.19.0.5" - "eclient-2:172.19.0.6" - "feign-1:172.19.0.7" - "config-server-1:172.19.0.8" - "service-2-1:172.19.0.9" - "apigateway-1:172.19.0.10" - "feign-2:172.19.0.11" - "mysql-1:172.19.0.12" ``` 运行如下命令启动第二个实例`eclient-2`: ``` docker-compose up -d eclient-2 ``` ## 三、创建Feign Client项目 在`spring-cloud-poc`目录下创建模块`feignClient`。然后创建启动类`com.ultimatech.feign.ServiceFeignApplication` ``` package com.ultimatech.feign; 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.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; /** * Created by zhangleping on 2017/9/27. */ @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients @EnableHystrix @EnableHystrixDashboard public class ServiceFeignApplication { public static void main(String[] args) { SpringApplication.run(ServiceFeignApplication.class, args); } } ``` `@EnableFeignClients`用来增加Feign Client的支持。 `@EnableHystrix`用来增加熔断器的支持。 在`spring-cloud-poc/feignClient/config`目录下,创建一个实例的启动配置文件`feign-1-bootstrap.yml` ``` spring: cloud: config: name: feign-1 label: master profile: prd eureka: client: serviceUrl: defaultZone: http://eureka-1:8761/eureka/,http://eureka-2:8761/eureka/ ``` 在上面的配置中,实例在启动时需要读取Config Server上的`/feign-1-prd.yml`配置文件,所以在`cloud-config`中我们加入`feign-1-prd.yml`文件,并`git push`到git服务器。 ``` eureka: instance: hostname: feign-1 server: hostname: eureka-1 client: serviceUrl: defaultZone: http://eureka-1:8761/eureka/,http://eureka-2:8761/eureka/ server: port: 8080 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 1000 #缺省为1000 ribbon: ReadTimeout: 10000 ConnectTimeout: 10000 maxAutoRetries: 3 ``` ## 四、实现调用`eurekaClient`服务 首先,编写接口`com.ultimatech.feign.service.ISchedualServiceHi` ``` package com.ultimatech.feign.service; import com.ultimatech.cloud.poc.base.model.Message; import com.ultimatech.cloud.poc.base.model.TestData; import com.ultimatech.cloud.poc.base.model.UserVo; import com.ultimatech.feign.service.impl.SchedualServiceHiImpl; import org.springframework.cloud.netflix.feign.FeignClient; 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.RequestParam; import java.util.ArrayList; import java.util.List; /** * Created by zhangleping on 2017/9/27. */ @FeignClient(value = "service-hi", fallback = SchedualServiceHiImpl.class) public interface ISchedualServiceHi { @RequestMapping(value = "/hi", method = RequestMethod.GET) String sayHiFromClientOne(@RequestParam(value = "name") String name); ...... } ``` `@FeignClient(value = "service-hi", fallback = SchedualServiceHiImpl.class)`指定了接口调用的服务名称是`service-hi`,这个服务名定义在`eclient-1-prd.yml`和`eclient-2-prd.yml`配置文件中: ``` spring: application: name: service-hi ``` 同一个服务的不同实例的配置文件`spring.application.name`必须是相同的,表示是同一个服务的不同实例。 我们可以将`eclient-1`和`eclient-2`看做是一个`service-hi`的服务的两个实例。Feign Client会把请求发送到`service-hi`的某一个实例上。 `fallback = SchedualServiceHiImpl.class`指定一个`ISchedualServiceHi`接口的实现。实现每一个接口方法在出现熔断时,如何处理返回值。我们如下实现熔断处理: ``` package com.ultimatech.feign.service.impl; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.ultimatech.cloud.poc.base.model.Message; import com.ultimatech.cloud.poc.base.model.TestData; import com.ultimatech.cloud.poc.base.model.UserVo; import com.ultimatech.feign.service.ISchedualServiceHi; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestParam; import java.util.List; /** * Created by zhangleping on 2017/10/13. */ @Component public class SchedualServiceHiImpl implements ISchedualServiceHi { private Gson gson=new GsonBuilder().create(); public String sayHiFromClientOne(@RequestParam(value = "name") String name) { return "Sorry, errors! " + name; } ...... } ``` 然后,我们实现一个`com.ultimatech.feign.controller.HiController`来对外提供访问端点,通过浏览器访问触发这些端点,让`feignClient`实例远程调用`service-hi`的接口。 ``` package com.ultimatech.feign.controller; import com.netflix.discovery.EurekaClient; import com.netflix.discovery.shared.Application; import com.netflix.discovery.shared.Applications; import com.ultimatech.cloud.poc.base.model.Message; import com.ultimatech.cloud.poc.base.model.TestData; import com.ultimatech.cloud.poc.base.model.UserVo; import com.ultimatech.feign.service.ISchedualServiceHi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * Created by zhangleping on 2017/9/27. */ @RestController public class HiController { @Autowired private ISchedualServiceHi serviceHi; @RequestMapping(value = "/hi",method = RequestMethod.GET) public String sayHi(@RequestParam String name){ return serviceHi.sayHiFromClientOne(name); } ...... } ``` 我们通过`@Autowired`将远程服务的Bean注入到Controller中(其他位置都可以这样注入),然后在对应的端点中,调用对应的方法。 最后编译安装本模块。 ## 五、部署feignClient实例 在`docker-compose.yml`的`services`中添加: ``` feign-1: build: ./docker/webnode container_name: feign-1 volumes: - "/tmp" - "./feignClient/target/feignClient-1.0-SNAPSHOT.jar:/app.jar" - "/config" - "./feignClient/config/feign-1-bootstrap.yml:/config/bootstrap-prd.yml" depends_on: - eureka-1 - eureka-2 - config-server-1 environment: HOSTNAME: feign-1 JAVA_OPTS: -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m networks: mynet: ipv4_address: 172.19.0.7 extra_hosts: - "eureka-1:172.19.0.2" - "eureka-2:172.19.0.3" - "eclient-1:172.19.0.5" - "eclient-2:172.19.0.6" - "feign-1:172.19.0.7" - "config-server-1:172.19.0.8" - "service-2-1:172.19.0.9" - "apigateway-1:172.19.0.10" - "feign-2:172.19.0.11" - "mysql-1:172.19.0.12" - "oauth2server-1:172.19.0.13" ports: - 8080:8080 ``` 运行启动命令: ``` docker-compose up -d feign-1 ``` ## 六、验证 通过浏览器访问: ``` http://localhost:8080/hi?name=aaa ``` 然后不停的刷新,我们会发现显示的内容不同,说明Feign Client在两个实例间不停的切换访问。 运行命令停止`service-hi`,即停止`eclient-1`和`eclient-2`: ``` docker-compose stop eclient-1 eclient-2 ``` 然后再刷新页面,我们会看到如下信息: ``` Sorry, errors! aaa ``` 正是我们定义的熔断返回信息。
上一篇:
Docker Swarm 深入浅出
下一篇:
Spring Cloud 教程|第三篇 开发部署一个服务
0
赞
557 人读过
新浪微博
微信
腾讯微博
QQ空间
人人网
提交评论
立即登录
, 发表评论.
没有帐号?
立即注册
0
条评论
More...
文档导航
没有帐号? 立即注册