在Spring-Cloud-OpenFeign源码解析-02-OpenFeign自动装配分析到OpenFeign 接口代理对象的创建是通过构建成一个 FeignClientFactoryBean 对象,并最后注入到容器中的,那么这个FeignClientFactoryBean是如何实现代理对象创建的呢?
FactoryBean
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
FactoryBean是Spring框架中的一个扩展接口,用于创建和管理其他Bean实例的对象。使用它可以生成某些需要复杂初始化过程的bean对象。当配置某个bean实现了FactoryBean接口时,该bean返回的对象不是FactoryBean本身,而是FactoryBean#getObject()方法返回的对象,这就提供了我们自定义创建对象的能力。
它与Spring其他bean的主要区别在于,FactoryBean负责产生其他bean实例。也即当我们从IOC容器中获取一个FactoryBean时,我们得到的是它创建的那个bean的实例,而不是FactoryBean的实例本身。
FeignClientFactoryBean
public class FeignClientFactoryBean
implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
@Override
public Object getObject() {
//调用getTarget()方法
return getTarget();
}
/**
* @param <T> the target type of the Feign client
* @return a {@link Feign} client created with the specified data and the context
* information
*/
<T> T getTarget() {
FeignContext context = beanFactory != null ? beanFactory.getBean(FeignContext.class)
: applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
// 判断当前FeignClient注解中的url是否为空,如果不为空,直接通过url的调用
if (!StringUtils.hasText(url)) {
if (LOG.isInfoEnabled()) {
LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing.");
}
//是否以http开头
if (!name.startsWith("http")) {
url = "http://" + name;
}
else {
url = name;
}
url += cleanPath();
//返回目标对象
return (T) loadBalance(builder, context, new HardCodedTarget<>(type, name, url));
}
if (StringUtils.hasText(url) && !url.startsWith("http")) {
url = "http://" + url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof FeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,
// but Spring Cloud LoadBalancer is on the classpath, so unwrap
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
if (client instanceof RetryableFeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,
// but Spring Cloud LoadBalancer is on the classpath, so unwrap
client = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
applyBuildCustomizers(context, builder);
Targeter targeter = get(context, Targeter.class);
//返回目标对象
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));
}
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
applyBuildCustomizers(context, builder);
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-loadbalancer?");
}
最终都会调用到targeter.target()方法
Targeter#target()
默认调用的是DefaultTargeter
class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
//继续调用target方法
return feign.target(target);
}
}
feign.target()
public abstract class Feign {
public <T> T target(Target<T> target) {
//创建代理对象
return build().newInstance(target);
}
//构建Feign对象
public Feign build() {
Client client = Capability.enrich(this.client, capabilities);
Retryer retryer = Capability.enrich(this.retryer, capabilities);
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Encoder encoder = Capability.enrich(this.encoder, capabilities);
Decoder decoder = Capability.enrich(this.decoder, capabilities);
//创建代理对象的InvocationHandler工厂实例
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
//最终返回ReflectiveFeign实例
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
ReflectiveFeign.newInstance()
public class ReflectiveFeign extends Feign {
@Override
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>();
//解析方法,封装为MethodHandler
for (Method method : target.type().getMethods()) {
//Object方法
if (method.getDeclaringClass() == Object.class) {
continue;
//Default方法
} 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);
//jdk动态代理创建对象
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
//返回代理对象
return proxy;
}
}
总结
通过创建FeignClientFactoryBean对象,在@Autowired或者@Resource注入FeignClient实例的时候,实际上返回的是FactoryBean#getObject()方法创建的对象,底层通过JDK动态代理Proxy.newProxyInstance()返回代理对象,具体的实现逻辑在InvocationHandler的invoke方法中
881

被折叠的 条评论
为什么被折叠?



