大家好,又见面了,我是你们的朋友全栈君。
一、feign测试代码
1.服务接口上标注@FeignClient
@FeignClient("order")
public interface OrderServiceFeign {
@GetMapping("/getOrder")
String getOrder();
}
2.调用方可以直接注入然后直接调用访问
代码语言:javascript复制@RestController
@RequestMapping("/feign")
public class FeignTestController {
@Autowired
private OrderServiceFeign orderServiceFeign;
@GetMapping("/order")
public String getOrder() {
return orderServiceFeign.getOrder();
}
}
3.在调用方的启动类上加上一个启动注解@EnableFeignClients
@SpringBootApplication
@EnableFeignClients
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
二、寻找入口
springcloud组件基本都是启动的注解,也就是@EnableFeignClients
1.@EnableFeignClients干了什么?
代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
我们看到Import注解里面有个FeignClientsRegistrar类,在spring中看到以Registrar结尾的类,就会想到spring的bean的动态装备,一个是selecter,一个是registrar.
简单介绍下registrar 比如我们要将类RegistrarBean 装在的spring 装载到spring容器
代码语言:javascript复制public class RegistrarBean {
}
定义一个类实现ImportBeanDefinitionRegistrar
接口,实现registerBeanDefinitions方法,然后通过registry的registerBeanDefinition可以注册一个实例到spring当中
public class SpringRegistrarTest implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName(RegistrarBean.class.getName());
registry.registerBeanDefinition("registrarBean",beanDefinition);
}
}
定义一个自定义注解,用Import注解导入我们上面写的SpringRegistrarTest 类
代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(SpringRegistrarTest.class)
public @interface EnableRegistrar {
}
将我们写的注解配置到启动类上
代码语言:javascript复制@SpringBootApplication
@EnableFeignClients
@EnableRegistrar
public class UserServiceApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(UserServiceApplication.class, args);
Object registrarBean = applicationContext.getBean("registrarBean");
System.out.println(registrarBean);
}
}
我们在返回的context对象去获取我们去注册的bean,是可以拿到的
我们接着看FeignClientsRegistrar这个类
代码语言:javascript复制public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// 注册默认的配置类
registerDefaultConfiguration(metadata, registry);
// 注册feign客户端
registerFeignClients(metadata, registry);
}
我们看registerFeignClients里面有这样几行代码
代码语言:javascript复制 BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
new String[] {
alias });
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
我们发现注册了一个FeignClientFactoryBean的类,它实现了FactoryBean,它提供了一个getObject方法,当我们依赖注入一个feign客户端对象的时候,这个方法就会被调用
代码语言:javascript复制public Object getObject() throws Exception {
// 获取FeignContext 对象
FeignContext context = applicationContext.getBean(FeignContext.class);
// 构建一个Feign.Builder 对象
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
String url;
if (!this.name.startsWith("http")) {
url = "http://" this.name;
}
else {
url = this.name;
}
url = cleanPath();
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, 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) {
client = ((LoadBalancerFeignClient)client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
1.获取FeignContext 对象,FeignContext 是怎么来的?
有一个自动装配类FeignAutoConfiguration
,创建了这个对象
FeignAutoConfiguration类
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
而且我们发现创建FeignContext中还调用了父类的构造器,传入了一个FeignClientsConfiguration
,
fegin会根据不同的服务创建不同的spring上下文,在创建不同的应用上下文时,这个类会被加载到上下文当中
FeignContext类
代码语言:javascript复制 public FeignContext() {
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}
FeignClientsConfiguration类 这个类创建了Decoder ,Encoder 对象,对数据进行编解码,相当于序列化和反序列化。有一个Contract对象, 这个对象是用的SpringMvcContract对象,这个对象是用来解析请求的一个模板的,不如请求方式,路径,参数等。 还有 Feign.Builder,日志工厂等对象。
代码语言:javascript复制@Configuration
public class FeignClientsConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Autowired(required = false)
private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
@Autowired(required = false)
private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
@Autowired(required = false)
private Logger logger;
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
}
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
return new SpringEncoder(this.messageConverters);
}
@Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) {
return new SpringMvcContract(this.parameterProcessors, feignConversionService);
}
@Bean
public FormattingConversionService feignConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
for (FeignFormatterRegistrar feignFormatterRegistrar : feignFormatterRegistrars) {
feignFormatterRegistrar.registerFormatters(conversionService);
}
return conversionService;
}
@Configuration
@ConditionalOnClass({
HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "feign.hystrix.enabled")
public Feign.Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
}
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
@Bean
@ConditionalOnMissingBean(FeignLoggerFactory.class)
public FeignLoggerFactory feignLoggerFactory() {
return new DefaultFeignLoggerFactory(logger);
}
2.构建一个Feign.Builder对象
代码语言:javascript复制protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
// @formatter:off
Feign.Builder builder = get(context, Feign.Builder.class)
// required values
.logger(logger)
.encoder(get(context, Encoder.class))
.decoder(get(context, Decoder.class))
.contract(get(context, Contract.class));
// @formatter:on
configureFeign(context, builder);
return builder;
}
在上下文当中去获取Feign.Builder,并设置编码,解码器,模板解析,日志等,这些对象都是在FeignClientsConfiguration 这个类中创建的。
代码语言:javascript复制 protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
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?");
}
在loadBalance方法中,又在builder,设置了一个client 对象,这个对象是LoadBalancerFeignClient
的这么一个对象,他在是FeignRibbonClientAutoConfiguration
这个自动装备类,有个Import注解的内容加载了一个DefaultFeignLoadBalancedConfiguration
对象,里面有如下代码
@Configuration
class DefaultFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new LoadBalancerFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
feign类
代码语言:javascript复制 public <T> T target(Target<T> target) {
return build().newInstance(target);
}
build返回了一个ReflectiveFeign对象
代码语言:javascript复制 public Feign build() {
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}
ReflectiveFeign类 可以看到返回一个代理对象
代码语言:javascript复制 public <T> T newInstance(Target<T> target) {
// 通过contract 将一个个方法解析成MethodHandler对象。实际上是SynchronousMethodHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
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);
for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@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();
}
return dispatch.get(method).invoke(args);
}
通过contract 将一个个方法解析成MethodHandler对象。实际上是SynchronousMethodHandler。
当请求过来后会进入到FeignInvocationHandler
的invoke
方法,最后获取相应的MethodHandler去执行
流程图
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/188893.html原文链接:https://javaforall.cn