springboot-fegin

一、大纲
还是自动装配的引子
大家都知道使用fegin,那肯定需要启用它
1、在启动类启用EnableFeignClients, 而这个直接被@import(FeignClientsRegistrar.class);
2、在FeignClientsRegistrar继承ImportBeanDefinitionRegistrar, 在这里面完成register到spring容器中。
在这个类会扫描出所有声明了@FeignClient下信息,加载这个类的路径,请求方式等注入到spring容器;注意这里是声明式接口,那么放入容器中的肯定是代理对象了。
所以这里就能想的到了,fegin他整合springmvc,hystrix,ribbon
先看看几个被自动装配的配置类

二、EnableFeignClients注入FeignClients声明接口spring容器(代理)
@EnableFeignClients

在接口注解@FeignClient(只能在接口上使用)

来看看feign怎么扫描进的spring容器中

前面我们知道了,会把所有注解过的@FeignClient的方法转成FeignClientFactoryBean注入到spring容器中。
来看看FeignClientFactoryBean这个方法类
看实现FactoryBean,从所周知,集成了FactoryBean,在spring启动的时候,会加载这个类下的集成类,并调用getObject方法

看看HystrixTargeter

三、接口调用,代理invoke
而我们在api层上直接调用接口,直接.出来的方法,就是动态代理去代用;声明式接口
看下动态代理的invoke方法

public class ReflectiveFeign extends Feign {
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if ("equals".equals(method.getName())) {
			try {
				Object otherHandler =
				args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
				return equals(otherHandler);
			} catch (IllegalArgumentException e) {
				return false;
			}
		} else if ("hashCode".equals(method.getName())) {
			return hashCode();
		} else if ("toString".equals(method.getName())) {
			return toString();
		}
		// 看下invoke执行了什么?
		return dispatch.get(method).invoke(args);
	}
}

final class SynchronousMethodHandler implements MethodHandler {
	@Override
	public Object invoke(Object[] argv) throws Throwable {
		RequestTemplate template = buildTemplateFromArgs.create(argv);
		Options options = findOptions(argv);
		Retryer retryer = this.retryer.clone();
		while (true) {
			try {
				return executeAndDecode(template, options);
			} catch (RetryableException e) {
				try {
					retryer.continueOrPropagate(e);
				} catch (RetryableException th) {
					Throwable cause = th.getCause();
					if (propagationPolicy == UNWRAP && cause != null) {
						throw cause;
					} else {
						throw th;
					}
				}
				if (logLevel != Logger.Level.NONE) {
					logger.logRetry(metadata.configKey(), logLevel);
				}
				continue;
			}
		}
	}

	//  这里就很属性的Request眼熟了。具体执行还是LoadBalanceFeignClient上执行。
	Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
		Request request = targetRequest(template);

		if (logLevel != Logger.Level.NONE) {
			logger.logRequest(metadata.configKey(), logLevel, request);
		}

		Response response;
		long start = System.nanoTime();
		try {
			// 这里;spring启动只是把被@FeignClient注解的声明式接口,
			// 使用动态代理注解到底spring容器里面,在.方法的,执行代理类里面的invoke;
			// 重点来看下这里
			response = client.execute(request, options);
			// ensure the request is set. TODO: remove in Feign 12
			response = response.toBuilder()
			.request(request)
			.requestTemplate(template)
			.build();
		} catch (IOException e) {
			if (logLevel != Logger.Level.NONE) {
				logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
			}
			throw errorExecuting(request, e);
		}
		
	}
}


四、集成ribbon-负载均衡
看下LoadBalanceFeignClient是怎么execute的。

@Override
public Response execute(Request request, Request.Options options) throws IOException {
	try {
		// 这里在获取http://test-service/url/test
		URI asUri = URI.create(request.url());
		// 获取test-service,通过这个clientName获取具体的请求地址
		String clientName = asUri.getHost();
		URI uriWithoutHost = cleanUrl(request.url(), clientName);
		FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
			this.delegate, request, uriWithoutHost);

		IClientConfig requestConfig = getClientConfig(options, clientName);
		return lbClient(clientName)
		// 这一步实现ribbon负载均衡
		.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
	}
	catch (ClientException e) {
		IOException io = findIOException(e);
		if (io != null) {
			throw io;
		}
		throw new RuntimeException(e);
	}
}

若有收获,就点个赞吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值