spring cloud openfeign 源码实例解析

网友投稿 433 2022-12-25


spring cloud openfeign 源码实例解析

一、读取注解信息

入口

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication

@EnableFeignClients

public class CjsPriceServiceApplication {

public static void main(String[] args) {

SpringApplication.run(CjsPriceServiceApplication.class, args);

}

}

spring boot 项目启动后会自动扫描application上面的注解,@EnableFeignClients的注解如下

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Documented

@Import(FeignClientsRegistrar.class)

public @interface EnableFeignClients {

。。。。

}

在注解中导入了 FeignClientsRegistrar类,用来像spring注册,EnableFeignClients和FeignClient上面开发人员添加的注解信息

@Override

public void registerBeanDefinitions(AnnotationMetadata metadata,

BeanDefinitionRegistry registry) {

registerDefaultConfiguration(metadata, registry);

registerFeignClients(metadata, registry);

}

二、当项目启动,读取@Autowired时会调用,实现了FactoryBean接口的FeignClientFactoryBean.getObject()方法

@Override

public Object getObject() throws Exception {

return getTarget();

}

T getTarget() {

FeignContext context = this.applicationContext.getBean(FeignContext.class);

Feign.Builder builder = feign(context);

if (!StringUtils.hasText(this.url)) {

if (!this.name.startsWith("http")) {

this.url = "http://" + this.name;

}

else {

this.url = this.name;

}

this.url += cleanPath();

return (T) loadBalance(builder, context,

new HardCodedTarget<>(this.type, this.name, this.url));

}

if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {

this.url = "http://" + this.url;

}

String url = this.url + cleanPath();

Client client = getOptional(context, Client.class);

if (client != null) {

if (client instanceof LoadBalancerFeignClient) {

// not load balancing because we have a url,

// but ribbon is on the classpath, so unwrap

client = ((LoadBalancerFeignClient) client).getDelegate();

}

builder.client(client);

}

Targeter targeter = get(context, Targeter.class);

return (T) targeter.target(this, builder, context,

new HardCodedTarget<>(this.type, this.name, url));

}

可以看到 getTarget()有两种返回结果的情况,其原理都一样后来调用了 targeter.target()方法

package org.springframework.cloud.openfeign;

import feign.Feign;

import feign.Target;

/**

* @author Spencer Gibb

*/

interface Targeter {

T target(FeignClientFactoryBean factory, Feign.Builder feign,

FeignContext context, Target.HardCodedTarget target);

}

默认实现类

package org.springframework.cloud.openfeign;

import feign.Feign;

import feign.Target;

/**

* @author Spencer Gibb

*/

class DefaultTargeter implements Targeter {

@Override

public T target(FeignClientFactoryBean factory, Feign.Builder feign,

FeignContext context, Target.HardCodedTarget target) {

return feign.target(target);

}

}

然后再看 feign.target(target);方法

public T target(Target target) {

return build().newInstance(target);

}

public Feign build() {

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);

return new ReflectiveFeign(handlersByName, invocationHandlerFacthttp://ory, queryMapEncoder);

}

}

build()方法返回了创建代理类的对象,然后调用了创建代理的 newInstance方法

public T newInstance(Target target) {

Map nameToHandler = targetToHandlersByName.apply(target);

Map methodToHandler = new LinkedHashMap();

List defaultMethhttp://odHandlers = new LinkedList();

for (Method method : target.type().getMethods()) {

if (method.getDeclaringClass() == Object.class) {

continue;

} else if (Util.isDefault(method)) {

DefaultMethodHandler handler = new DefaultMethodHandler(method);

defaultMethodHandlers.add(handler);

methodToHandler.put(method, handler);

} else {

methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));

}

}

InvocationHandler handler = factory.create(target, methodToHandler);

T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),

new Class>[] {target.type()}, handler);

http:// for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {

defaultMethodHandler.bindTo(proxy);

}

return proxy;

}

最后,当我们项目中使用 @Autowired注入时,就回调用工厂类 FeignClientFactoryBean方法的 getObject()方法 返回我们的代理对象


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java如何获取系统CPU、内存占用
下一篇:JAVA利用递归删除文件代码实例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~