在分析源码前,还是先介绍一下简单的使用流程。
首先引入依赖
org.springframework.cloud spring-cloud-starter-openfeign
开启自动Feign客户端功能
@SpringBootApplication
//可以配置扫描的Feign客户端包路径,不配置则为TestApplication.class包下
@EnableFeignClients
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class);
}
}
定义FeignClient
//可以添加一些配置,例如服务名,url之类
@FeignClient
public interface TestFeignClient{
//Spring MVC,调用地址要和服务提供方一致
@RequestMapping
public String geta();
}
openfeign的基本使用就是这样,然后加上自己所需要的配置即可。接下来就开始分析openfeign是如何开启,并如何实现远程调用的原理。
@EnableFeignClients开启Feign功能@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@documented
//FeignClients注册器
@import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
//注解的配置
//......
}
//实现了importBeanDefinitionRegistrar接口,去看registerBeanDefinitions()方法
class FeignClientsRegistrar implements importBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware
#FeignClientsRegistrar
public void registerBeanDefinitions(Annotationmetadata metadata,
BeanDefinitionRegistry registry) {
//注册@EnableFeignClients上定义的defaultConfiguration默认配置类
registerDefaultConfiguration(metadata, registry);
//扫描所有的@FeignClient注解
registerFeignClients(metadata, registry);
}
注册默认配置类
#FeignClientsRegistrar
private void registerDefaultConfiguration(Annotationmetadata metadata,
BeanDefinitionRegistry registry) {
//获取@EnableFeignClients配置的信息
Map defaultAttrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
//判断是否配置了defaultConfiguration
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
//判断配置在defaultConfiguration是否为内部类,拼接对应的类名
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
}
else {
name = "default." + metadata.getClassName();
}
//跟进去
registerClientConfiguration(registry, name,
defaultAttrs.get("defaultConfiguration"));
}
}
#FeignClientsRegistrar
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
//将@EnableFeignClients中的配置信息注册到容器中
registry.registerBeanDefinition(
name + "." + FeignClientSpecification.class.getSimpleName(),
builder.getBeanDefinition());
}
扫描@FeignClient注解
#FeignClientsRegistrar
public void registerFeignClients(Annotationmetadata metadata,
BeanDefinitionRegistry registry) {
//获取类路径扫描器
ClassPathScanningCandidateComponentProvider scanner = getScanner();
//设置资源加载器
scanner.setResourceLoader(this.resourceLoader);
Set basePackages;
//获取@EnableFeignClients的注解信息
Map attrs = metadata
.getAnnotationAttributes(EnableFeignClients.class.getName());
//创建@FeignClient类型的过滤器
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
FeignClient.class);
final Class>[] clients = attrs == null ? null
: (Class>[]) attrs.get("clients");
if (clients == null || clients.length == 0) {
scanner.addIncludeFilter(annotationTypeFilter);
//获取包路径
basePackages = getbasePackages(metadata);
}
else {
//......
}
//遍历包路径
for (String basePackage : basePackages) {
//获取该包路径下带@FeignClient的BD信息
Set candidateComponents = scanner
.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
Annotationmetadata annotationmetadata = beanDefinition.getmetadata();
Assert.isTrue(annotationmetadata.isInterface(),
"@FeignClient can only be specified on an interface");
//获取@FeignClient的注解信息
Map attributes = annotationmetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());
//获取@FeignClient上配置的名称,优先级为contextId>value>name>serviceId
String name = getClientName(attributes);
//注册@FeignClient的配置信息
registerClientConfiguration(registry, name,
attributes.get("configuration"));
//注册加了@FeignClient的类到容器中
registerFeignClient(registry, annotationmetadata, attributes);
}
}
}
}
#FeignClientsRegistrar
private void registerFeignClient(BeanDefinitionRegistry registry,
Annotationmetadata annotationmetadata, Map attributes) {
//返回添加了@FeignClient注解的Class的全限定名, 包名.类名
String className = annotationmetadata.getClassName();
//FeignClientFactoryBean是一个FactoryBean,用它来创建具体的FeignClient
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
//向FeignClientFactoryBean添加@FeignClient中配置的一些注解信息
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
String name = getName(attributes);
definition.addPropertyValue("name", name);
String contextId = getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] { alias });
//将FeignClientFactoryBean注册到容器中
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
这一步完成后,所有的加了@FeignClient的类就会被解析成FeignClientFactoryBean类型的BeanDefinition加入到容器中,FeignClientFactoryBean包含了@FeignClient上配置的信息,以及保存了当前添加@FeignClient注解的Class名称。之后就是Spring容器在refresh()内会去实例化该FeignClient,而FeignClientFactoryBean是FactoryBean类型,所以会调用它的getObject()进行实例化。
FeignClient实例化#FeignClientFactoryBean
public Object getObject() throws Exception {
return getTarget();
}
#FeignClientFactoryBean
T getTarget() {
//获取FeignContext,在FeignAutoConfiguration自动装配进来
FeignContext context = this.applicationContext.getBean(FeignContext.class);
//创建builder对象,用来生成Feign
Feign.Builder builder = feign(context);
//如果没有在@FeignClient配置了url,说明要负载均衡
if (!StringUtils.hasText(this.url)) {
//构造url
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
//http://服务名
this.url += cleanPath();
//创建负载均衡代理类
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
//说明url存在,使用硬编码的方式
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
//直接拼接url
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
//获取客户端对象
Client client = getOptional(context, Client.class);
if (client != null) {
//Ribbon客户端对象LoadBalancerFeignClient
if (client instanceof LoadBalancerFeignClient) {
client = ((LoadBalancerFeignClient) client).getDelegate();
}
builder.client(client);
}
//在FeignAutoConfiguration自动装配进来
Targeter targeter = get(context, Targeter.class);
//生成动态代理对象
return (T) targeter.target(this, builder, context,
new HardCodedTarget<>(this.type, this.name, url));
}
先来看看FeignAutoConfiguration都装配了什么Bean
FeignAutoConfiguration自动装配@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class,
FeignHttpClientProperties.class })
public class FeignAutoConfiguration {
//FeignContext,内部保存了创建FeignClient所需的组件
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
//以下是两个相对的条件
@Configuration
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")//引入hystrix
protected static class HystrixFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
//创建Hystrix类型
return new HystrixTargeter();
}
}
@Configuration
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")//未引入hystrix
protected static class DefaultFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
//创建默认类型
return new DefaultTargeter();
}
}
//下面还有HttpClient,Okhttp的配置
}
FeignAutoConfiguration配置类会自动装配一些用来创建FeignClient实例的Bean信息。
创建生成Feign的Builder对象#FeignClientFactoryBean
protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
//设置Logger、Encoder、Decoder等组件
Feign.Builder builder = get(context, Feign.Builder.class)
.logger(logger)
.encoder(get(context, Encoder.class))
.decoder(get(context, Decoder.class))
.contract(get(context, Contract.class));
//配置builder
configureFeign(context, builder);
return builder;
}
#FeignClientFactoryBean
protected void configureFeign(FeignContext context, Feign.Builder builder) {
FeignClientProperties properties = this.applicationContext
.getBean(FeignClientProperties.class);
//从.properties配置文件中加载配置
if (properties != null) {
if (properties.isDefaultToProperties()) {
configureUsingConfiguration(context, builder);
configureUsingProperties(
properties.getConfig().get(properties.getDefaultConfig()),
builder);
configureUsingProperties(properties.getConfig().get(this.contextId),
builder);
}
else {
configureUsingProperties(
properties.getConfig().get(properties.getDefaultConfig()),
builder);
configureUsingProperties(properties.getConfig().get(this.contextId),
builder);
configureUsingConfiguration(context, builder);
}
}
//配置类@Bean加载配置
else {
configureUsingConfiguration(context, builder);
}
}
在加载配置到builder对象中后,就是去生成代理对象的逻辑。
创建Feign代理对象首先来看看创建负载均衡代理对象
#FeignClientFactoryBean protectedT loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget target) { //获取客户端对象 Client client = getOptional(context, Client.class); if (client != null) { builder.client(client); //获取Targeter,分别有HystrixTargeter和DefaultTargeter类型 Targeter targeter = get(context, Targeter.class); //创建代理对象,跟进去,是一个接口方法,分别对应上面两种类型的实现 return targeter.target(this, builder, context, target); } throw new IllegalStateException( "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); }
先分析DefaultTargeter类型的代理对象
DefaultTargeter创建代理对象#DefaultTargeter publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { return feign.target(target); } #Feign public T target(Target target) { //跟进去 return build().newInstance(target); } #Feign.Builder public Feign build() { //构建SynchronousMethodHandler工厂 SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy); //设置组件对象 ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, errorDecoder, synchronousMethodHandlerFactory); //创建ReflectiveFeign实例,invocationHandlerFactory是InvocationHandlerFactory.Default类型 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); } #ReflectiveFeign 是Feign的实现类 public T newInstance(Target target) { //target内部保存了当前加了@FeignClient的接口Class,apply()会解析出接口中的方法和方法上的注解 //key是方法名,value是SynchronousMethodHandler类型,内部持有这个方法和注解的所有信息 Map nameToHandler = targetToHandlersByName.apply(target); Map methodToHandler = new linkedHashMap (); List defaultMethodHandlers = new linkedList (); //target.type()就是获取接口的Class //遍历所有的接口方法 for (Method method : target.type().getMethods()) { if (method.getDeclaringClass() == Object.class) { //Object的方法不管 continue; } else if (Util.isDefault(method)) { //default 类型的方法,要加入到defaultMethodHandlers集合 DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { //非Object,default的方法,从nameToHandler中取出添加到methodToHandler集合 methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } //InvocationHandler工厂创建InvocationHandler对象 InvocationHandler handler = factory.create(target, methodToHandler); //创建代理对象 T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class>[] {target.type()}, handler); for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) { //将default方法绑定在代理对象上 defaultMethodHandler.bindTo(proxy); } //返回代理对象 return proxy; }
到这里代理对象也创建完成了,接下来就该去看看InvocationHandler的invoke方法是在哪实现的。
InvocationHandler对象调用invoke()#InvocationHandlerFactory.Default public InvocationHandler create(Target target, MapDefaultMethodHandler的invoke()dispatch) { //创建了FeignInvocationHandler类型的InvocationHandler,直接看它的invoke方法 return new ReflectiveFeign.FeignInvocationHandler(target, dispatch); } #FeignInvocationHandler 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(); } //dispatch就是在构造中赋值的,在#ReflectiveFeign的newInstance()方法中的methodToHandler //key为接口中的方法,value为SynchronousMethodHandler和DefaultMethodHandler类型 //所以接下来就去看这两个类型的invoke方法 return dispatch.get(method).invoke(args); }
public Object invoke(Object[] argv) throws Throwable {
if (handle == null) {
throw new IllegalStateException(
"Default method handler invoked before proxy has been bound.");
}
//default修饰的方法就直接执行
return handle.invokeWithArguments(argv);
}
SynchronousMethodHandler的invoke()
public Object invoke(Object[] argv) throws Throwable {
//将方法参数构建成RequestTemplate,这个对象相信大家都很熟悉
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);
}
//......
}
}
}
#SynchronousMethodHandler
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
//调用RequestInterceptor,根据template生成Request对象
Request request = targetRequest(template);
//......
//响应对象
Response response;
long start = System.nanoTime();
try {
//调用客户端的execute执行请求
response = client.execute(request, options);
} catch (IOException e) {
//......
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
boolean shouldClose = true;
try {
//......
//对response进行解码
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
}
//......
}
真正执行请求的client.execute(request, options)是一个接口方法,是由不同的客户端工具进行实现。如果没有导入Ribbon,那么就用feign自带的Client.Default内部进行实现。Client是一个接口。
#Client.Default
public Response execute(Request request, Options options) throws IOException {
//convertAndSend()发送请求
HttpURLConnection connection = convertAndSend(request, options);
//convertResponse()响应解码
return convertResponse(connection, request);
}
如果导入了Ribbon,那么就是LoadBalancerFeignClient实现,内部使用Ribbon进行负载均衡
#LoadBalancerFeignClient
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
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)
.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
}
//......
}
到这里,没有导入Hystrix创建代理对象的流程就分析完了,一些具体解析的方法并没有去详细分析,因为我们主要是理解openfeign的执行流程,所以分析创建代理对象,然后到真正执行请求的地方就行了。接下来是去分析引入了Hystrix后是如何创建代理。
HystrixTargeter创建代理对象#HystrixTargeter publicT target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget target) { //判断是否为HystrixFeign类型 if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { //这里会调用ReflectiveFeign的那段逻辑 return feign.target(target); } feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId(); SetterFactory setterFactory = getOptional(name, context, SetterFactory.class); if (setterFactory != null) { builder.setterFactory(setterFactory); } //是否设置降级 Class> fallback = factory.getFallback(); if (fallback != void.class) { return targetWithFallback(name, context, target, builder, fallback); } Class> fallbackFactory = factory.getFallbackFactory(); if (fallbackFactory != void.class) { return targetWithFallbackFactory(name, context, target, builder, fallbackFactory); } //执行到这说明没有设置降级,又会回到ReflectiveFeign return feign.target(target); }
虽然导入了Hystrix,但是内部还是会判断是否设置过降级,如果没有,会回到普通的调用链路。上面的降级分支最终都会合并到一起,所以分析一个方法就行。
#HystrixTargeter privateT targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget target, HystrixFeign.Builder builder, Class> fallback) { T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type()); //创建代理对象,跟进去 return builder.target(target, fallbackInstance); } #HystrixFeign.Builder public T target(Target target, T fallback) { //newInstance会回到ReflectiveFeign逻辑,我们关心的是引入hystrix后,InvocationHandler的类型 //在build中会设置InvocationHandlerFactory的类型 return build(fallback != null ? new FallbackFactory.Default (fallback) : null) .newInstance(target); } #HystrixFeign.Builder Feign build(final FallbackFactory> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Map dispatch) { //最终返回了HystrixInvocationHandler实例,所以去看它的invoke方法 return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); } #HystrixInvocationHandler public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { //...... HystrixCommand
到这里Hystrix的代理逻辑也分析完了,它和默认创建代理对象的逻辑就是invoke()的实现不同,它只是对请求加了熔断降级的处理,其他的流程基本一致。
以上就是openfeign源码分析的整体流程,首先从feign的功能是如何开启的开始分析,然后到FeignClient是如何添加到容器当中,接着分析FeignClient是如何被代理创建,最后分析了默认方式和引入Hystrix的方式分别是如何执行的。总的来说,如果只是理解openfeign的大概执行流程,了解这么多已经足够了,但还想知道一些对象具体是如何解析创建出来、请求响应是如何执行的,那请大家自行研究。



