Feign源码解析之注入IOC容器
Feign源码解析之生成jdk动态代理
上面两篇文章分析了在springboot中feign是如何注入IOC容器并生成jdk动态代理类的,下面我们将着重分析一下feign的代理类的处理逻辑,看一看代理类是如何将接口里的方法转化成http请求的。
之前的文章有提到,在通过FeignClientFactoryBean的getObject方法生成代理类的过程中是根据applicationContext和配置文件获取到其中的属性值的,因此我们可以通过将特定类注入IOC容器或者修改配置的方式实现自定义的实现方式。所以,在文章开始之前首先声明,下文中的分析全部基于springboot中的feign的默认实现。
一. Feign的配置类
首先,feign在springboot中主要有两个配置类,其中的自动配置类FeignAutoConfiguration在之前的文章中已经有提到,下面我们了解一下另一个配置类FeignClientsConfiguration,这个类是在FeignContext的父类方法createContext中的context.register(PropertyPlaceholderAutoConfiguration.class,this.defaultConfigType);
语句注入各个client所属的applicationContext中的。
@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);
}
}
FeignClientsConfiguratiob中注入的几个类都是在生成并使用代理类过程中的属性的默认值。
二. FeignInvocationHandler类的invoke方法
接着我们继续看动态类的执行方法:FeignInvocationHandler类的invoke方法,可以发现其执行逻辑为从dispatch中根据method获取到对应的methodHandle以执行invoke方法。
@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);
}
由于dispatch属性是由ReflectiveFeign类调用FeignInvocationHandle的构造方法时传入的,我们需要进入ReflectiveFeign的newInstance方法关注dispatch的值。
public <T> T newInstance(Target<T> target) {
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;
}
局部变量methodToHandler即传入FeignInvocationHandle的dispatch属性,遍历feignClient接口的方法进行组装,分3中情况:
1.从object类继承而来的方法,忽略。这一点也和FeignInvocationHandle的invoke方法针对equal、hashcode、toString方法的处理吻合。
2.接口中的default方法,对应的methodHandle的逻辑依旧还是原方法的逻辑
3.其它方法ÿ