spring cloud 10 feign

一、服务调用
服务调用和消息一般是两个维度,
1,服务调用是同步的
2,消息是异步的回调,事件的一个周期

二、准备
• 远程过程调用(RPC)

• 接口定义语言(IDL)
interface definition language

• 通讯协议(Protocol)
HTTP,web-socket,Socket

• Netflix Feign
契约式编程
springcloud将Feign和spring mvc整合

• Spring Cloud 技术回顾 (服务短路 、负载均衡、服务发现、分布式配置等)

image.png

三、
1,NOSQL:redis,elasticsearch,mongodb
2,integration:rabbitmq,kafka,
3,config:config client/config server/zookeeper config/consul config
4,discovery:eureka server,eureka discovery,zookeeper discovery,consul discovery
5,routing:zuul,gateway,ribbon,feign
6,circuit breaker:hystrix,turbine

四、核心概念
1,远程过程调用(RPC)
remote procedure call,通过网络进行传输。
一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序(进程),而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。
• 例如
• Java RMI(二进制协议)进程之间的协议,必须用POJO(序列化&反序列化)
• WebServices(文本协议)一般都有骨架或者说是结构,比如XML schema

2,消息传递
RPC 是一种请求-响应协议,一次 RPC在客户端初始化,再由客户端将请求消息传递到远程的服务器,执行指定的带有参数(这里的参数和方法的参数有所区别。这里的参数也有可能是请求头之类的信息)的过程。经过远程服务器执行过程后,将结果作为响应内容(响应头和响应体)返回到客户端。

3,存根(Stub)
在一次分布式计算 RPC 中,客户端和服务器转化参数(不仅仅是方法的参数)的一段代码。 由于存根的参数转化,RPC执行过程如同本地执行函数调用。存根必须在客户端和服务器两端均装载,并且保持兼容(比如高版本的服务端兼容低版本的客户端调用)。

HTTP调用的存根在于内部的实现。web服务器和客户端都支持HTTP协议的话,那么协议的内容和格式就是存根。
如果是java rmi(remote method invoke)的话,两边都必须要有接口,传输的模型对象必须序列化,类的版本要保持一致,pojo的字段也要兼容。
java 序列化主要关注POJO字段的状态,对pojo的方法不是很关注。

五、spring cloud feign
• 依赖
• org.springframework.cloud:spring-cloud-starter-feign
• 激活
• @EnableFeignClients (标记在服务调用方的SpringApplication上)
• 申明
• @FeignClient 标记在接口Api上,name="服务提供方的service id"

申明@FeignClient API,name属性尽量使用占位符,避免硬编码。

package com.xixi.spring.cloud8.server.api;

import com.xixi.spring.cloud8.server.domain.User;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

/**
 * 用户服务
 * 声明Feign客户端,feigncliet里面的方法将会映射到rest api
 * ${user-service-name}指向user-service-provider
 */
@FeignClient(name = "${user-service-name}")//利用占位符,避免未来整合硬编码
public interface UserService {

    /**
     * 保存用户
     * @param user
     * @return
     */
    @PostMapping("/user/save")
    boolean saveUser(@RequestBody User user);


    /**
     * 查询所有的用户列表
     * @return
     */
    @GetMapping("/user/list")
    List findAll();
}

在user-service-client客户端激活@EnableFeignClients,放在服务调用方上,申明要激活的接口。在这里是UserService.class

@EnableFeignClients(clients = {UserService.class})
public class UserServiceClientApplication{}

六、默认组件
• Decoder/Encoder : ResponseEntityDecoder / SpringEncoder
• Logger : Slf4jLogger
• Contract : SpringMvcContract
原生的feign并不支持我们spring mvc的annotation(@RequestMapping),但是和spring结合以后就支持了,靠SpringMvcContract
如果想自己扩展,可以实现Contract,Contract的作用就是Define what annotations and values are valid on interfaces.
• Feign.Builder : HystrixFeign.Builder
• Client : LoadBalancerFeignClient( Ribbon 激活的话)

feign的底层还是ribbon LoadBalancerClient那一套,

七、• 整合负载均衡: Netflix Ribbon

1,user-service-client的配置文件application.properties

###ribbon 客户端应用
spring.application.name = user-ribbon-client

eureka.client.enabled = false
##服务提供方名称
provider.service.name = user-service-provider
##服务提供方主机
provider.service.host = localhost
###服务提供方端口
provider.service.port = 8081
server.port = 8080


##关闭eureka注册,通过显示地配置服务端的地址
##定义服务提供方地址,为RibbonLoadBalancerClient提供服务列表,如果有多个可以用逗号隔开。
user-service-provider.ribbon.listOfServers = \
  http://${provider.service.host}:${provider.service.port}

##配置自定义实现的MyPing,这样就不用@Bean去配置IPing,
# user-service-provider是要被负载均衡的服务
user-service-provider.ribbon.NFLoadBalancerPingClassName=\
  com.xixi.spring.cloud8.server.user.ribbon.client.ping.MyPing

###配置@FeignClient(name = "${user.service.name}")中的占位符
#user.service.name需要制定user service接口的提供方,也就是user-service-provider
user.service.name = ${provider.service.name}

2,服务调用方激活@EnableFeignClients,使用user-service调用服务
在UserRibbonController中注入userServiceFeignClient

  /**
   * 同一个接口不建议在客户端和服务端之间共享,实际情况最好使用组合UserService的方式
   * FeignClient标记的接口可以直接注入,Feign会动态代理帮我们去构造它的实现类
   */
  @Autowired
  private UserService userServiceFeignClient;

  @GetMapping("/user/list")
  public List getUserList2() {

    return userServiceFeignClient.findAll();
  }

3,服务端实现user-service API,暴露Rest接口
首先,

@Service("inMemoryUserService")
public class InMemoryUserService implements UserService

其次,
user-service-provider是最终的服务提供方,不需要标记为feignClient
UserServiceProviderController implements UserService
UserServiceProviderController实现feignclient接口。

最后,

  //由于UserServiceProviderController继承了UserService,所以这块可以不写@PostMapping("/user/save")。Feign Inheritance Support
  //注意:@PostMapping会被继承,但是@RequestBody,@RequestParam是不会被继承的,method parameter mapping is not inherited
  //这是因为java语言的特性决定的,方法外面的东西可以从父类继承,但是方法里面的实现,子类会覆盖父类。
  //URL映射可以从父类继承。PostMapping("/user/save")
  @Override
  public boolean saveUser(@RequestBody User user) {
    return userService.saveUser(user);
  }

八、• 整合服务短路: Netflix Hystrix
1,调整UserService api

package com.xixi.spring.cloud10.server.api;

import com.xixi.spring.cloud10.server.domain.User;

import com.xixi.spring.cloud10.server.fallback.UserServiceFallback;
import java.util.List;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**被标记为@FeignClient的接口,将会伪装UserService的客户端去调用它要调用的服务
 * 用户服务
 * 声明Feign客户端,feign client里面的方法将会映射到rest api
 * ${user-service-name}指向user-service-provider
 *
 * 整合Hystrix Fallback
 */
@FeignClient(name = "${user.service.name}",//利用占位符,避免未来整合硬编码
    primary = true,//primary = true表示当UserService有多个实现类的时候,FeignClient动态代理的那个实现类优先级最高
    fallback = UserServiceFallback.class )
public interface UserService {

    /**
     * 保存用户
     * @param user
     * @return
     */
    @PostMapping("/user/save")
    boolean saveUser(@RequestBody User user);


    /**
     * 查询所有的用户列表
     * @return
     */
    @GetMapping("/user/list")
    List findAll();
}


写一个UserServiceFallback

package com.xixi.spring.cloud10.server.fallback;

import com.xixi.spring.cloud10.server.api.UserService;
import com.xixi.spring.cloud10.server.domain.User;
import java.util.Collections;
import java.util.List;

public class UserServiceFallback implements UserService {

  @Override
  public boolean saveUser(User user) {
    return false;
  }

  @Override
  public List findAll() {
    return Collections.emptyList();
  }
}

2,在user-service-provider上整合@HystrixCommand

  @HystrixCommand(commandProperties = {
      //设置超时时间为100ms
      @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100")
  },
      //通过@HystrixCommand#fallbackMethod()实现异常处理,设置fallback方法,会在当前类或是他的父类里面去找fallbackForGetUsers()
      fallbackMethod = "fallbackForGetUsers")
  public List findAll() {
    return userService.findAll();
  }

九、• 整合服务发现: Netflix Eureka
(废弃ribbon白名单配置的方式,使用eureka获取服务列表)
1,写一个eureka-server
(1)引入eureka-server jar
(2)写引导类
(3)配置文件application.properties
2,user-service-client增加服务发现配置
(1)加依赖

    
      org.springframework.cloud
      spring-cloud-starter-netflix-eureka-client
    

(2)引导类激活服务发现@EnableDiscoveryClient
(3)application.properties,注意要注释掉之前白名单的配置

eureka.client.enabled = true
###连接eureka server
eureka.server.hostname = localhost
eureka.server.port = 8083
eureka.client.serviceUrl.defaultZone = \
  http://${eureka.server.hostname}:${eureka.server.port}/eureka

3,user-service-provider增加服务发现配置
(1)加依赖
(2)引导类加注解@EnableDiscoveryClient
(3)application.properties

十、• 整合配置服务器: Config Server
(1)加依赖

    s
      org.springframework.cloud
      spring-cloud-config-server
    

(2)引导类加注解@EnableDiscoveryClient,@SpringBootApplication,@EnableConfigServer
(3)application.properties

1,配置user-service.properties

###user-service-client配置内容,作为user-service-client配置内容的一部分,
# user-service-client本身也会有自己的application.properties
##如果有冲突,user-service的配置内容优先
##服务提供方名称
provider.service.name = user-service-provider
##服务提供方主机
#provider.service.host = localhost
####服务提供方端口
#provider.service.port = 8081

###配置@FeignClient(name = "${user.service.name}")中的占位符
#user.service.name需要制定user service接口的提供方,也就是user-service-provider
user.service.name = ${provider.service.name}

2,

3,

十一、• 整合配置客户端: Config Client

你可能感兴趣的:(spring cloud 10 feign)