帆的博客

扬帆起航

Feign和Hystrix结合使用

在@FeignClient中增加fallback配置,指定降级方法的执行

1
2
3
4
5
6
7
8
9
10
11
12
13
@FeignClient(name = "user",url = "${user.url}",fallback = UserFeignFallback.class
/*fallbackFactory = UserFeignFactory.class*/)
public interface UserFeign {

@PostMapping
void save(User user);

@GetMapping("/{id}")
User getUserByID(@PathVariable("id") String id);

@GetMapping
List<User> findAll();
}
阅读全文 »

Feign超时和重试

超时

在微服务架构中,一个服务对服务的访问至少得配置一个超时时间,不可能请求一个接口等了好几分钟都还没有返回,在设置超时时间后,超时后就认为这次接口请求失败了。

重试

服务B调用服务A,服务A部署了3台机器,现在服务B通过负载均衡的算法,调用到了服务A的机器1,因为服务A的机器1宕机了,请求超时了,可以让服务B再次请求一次服务A的机器1,如果还是不行,再请求服务A的机器2,如果还是不行,就再请求服务A的服务3,这就是重试机制。

阅读全文 »

接口方法与MethodHandler映射map的生成机制

在开始之前,先说一下FeignClient接口的上的SpringMVC注解是如何被解析的,回顾到之前生成动态代理的时候,有个nameToHandler的map,有一句非常关键的代码。

1
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);

这里面就完成了SpringMVCContract对方法的解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ReflectiveFeign.java
public Map<String, MethodHandler> apply(Target key) {
// 这就用contract完成了方法上的SpringMVC注解的转换
// ServiceAClient的每一个方法都会被解析成MethodMetadata
// 对各种SpringMVC的注解进行解析,将解析出来的header,method,path,body,form param,返回值等等等,放入了MethodMetadata中
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
// 遍历方法元数据
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md);
}
// 在这里就创建了SynchronousMethodHandler,key就是方法名
// SynchronousMethodHandler就是所有的方法被代理后实际处理的处理器
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
阅读全文 »

动态代理创建FeignClient的实例

在做完前面的事情以后,FeignClientFactoryBean已经被注册到Spring上下文中,根据Spring的原理,FactoryBean是用于构造复杂对象实例的一种工厂,可定制创建,初始化,刷新,销毁的各个过程。重点需要去看getObject()方法,看对象实例是如何产生的。

阅读全文 »

Feign的组件简介

Feign负责简化接口调用,发起Http请求,Feign也包含了几个核心组件

  1. 编码器和解码器:Encoder和Decoder。
    Encoder:如果调用接口的时候,传递的参数是个对象,feign需要将这个对象进行encode解码,json序列化,把一个对象转成json格式。
    Decoder:json反序列化,收到json以后,将json转换成本地的一个Java对象。
  2. Logger:用于打印接口请求相关的调用日志
  3. Contract:feign注解和spring web mvc 支持的@PathVariable,@RequesstMapping,@RequestParam等注解结合起来使用了。feign本来是没法支持spring web mvc的注解的,但是有了contract(契约组件)支持后,这个组件负责解释其他的注解,让feign可以跟其他注解结合起来使用。
  4. Feign.Builder:Feign客户端的一个实例构造器,基于构建器模式的,Ribbon也有。
  5. FeignClient:最核心的入口,和RibbonLoadBalancerClient类似,包含以上这些核心的组件,基于这些组件去协作调用。
阅读全文 »

负载均衡

服务注册,就是在分布式系统中,将注册的ip和端口号等信息告诉注册中心。

服务发现就是客户端去注册中心获取服务列表,知道每一个服务实例的ip和端口是什么。

负载均衡就是在拿到了这个服务列表以后,从中要选取一个实例来进行调用,这里就需要用到负载均衡算法。在Spring Cloud中,Ribbon就是做负载均衡用的一个组件,在这边叫做客户端负载均衡。具体的概念咋回事和如何使用我这里就不介绍了,网上文章很多,用过SpringCloud的人也应该都用过,下面开始进入源码探索。

阅读全文 »

服务心跳流程分析

eureka client每隔一定的时间,会给eureka server发送心跳,保持心跳,让eureka server认为自己还活着。

心跳在代码里,叫做续约。

  1. 还是在DiscoveryClient初始化的时候,有一个心跳的定时任务,由HeartbeatThread执行。

  2. 默认值是每隔30秒去发送一个心跳。DEFAULT_LEASE_RENEWAL_INTERVAL

  3. 接下来是用jersy去给eureka server发送心跳的http请求。

    阅读全文 »

eureka client全量抓取注册表

eureka client第一次启动的时候,会从eureka server端抓取全量的注册表,在本地进行缓存。后续每隔30秒从eureka server端抓取增量的注册表信息,和本地缓存进行合并。

先找到第一次抓取全量注册表的源码,没记错的话应该是在创建DiscoveryClient的构造方法里。就是下面这几行代码:

1
2
3
if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) {
fetchRegistryFromBackup();
}
阅读全文 »

eureka client启动流程

上一篇文章,我们分析了eureka server的启动流程,这一篇来分析一下eureka client的启动流程。我们先要找到启动入口在哪里。在eureka-examples里,有一个ExampleEurekaClient的测试类。要执行这个类,首先需要复制一段代码,设置一些基础属性,这是从eureka-server的单元测试里复制过来的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* This will be read by server internal discovery client. We need to salience it.
*/
private static void injectEurekaConfiguration() throws UnknownHostException {
String myHostName = InetAddress.getLocalHost().getHostName();
String myServiceUrl = "http://" + myHostName + ":8080/v2/";

System.setProperty("eureka.region", "default");
System.setProperty("eureka.name", "eureka");
System.setProperty("eureka.vipAddress", "eureka.mydomain.net");
System.setProperty("eureka.port", "8080");
System.setProperty("eureka.preferSameZone", "false");
System.setProperty("eureka.shouldUseDns", "false");
System.setProperty("eureka.shouldFetchRegistry", "false");
System.setProperty("eureka.serviceUrl.defaultZone", myServiceUrl);
System.setProperty("eureka.serviceUrl.default.defaultZone", myServiceUrl);
System.setProperty("eureka.awsAccessId", "fake_aws_access_id");
System.setProperty("eureka.awsSecretKey", "fake_aws_secret_key");
System.setProperty("eureka.numberRegistrySyncRetries", "0");
}
阅读全文 »
0%