初始化
一、初始化触发点:@EnableFeignClients
Spring Boot 应用启动时,@EnableFeignClients
注解会触发 Feign 的初始化:
@SpringBootApplication
@EnableFeignClients // 关键启动注解
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
二、核心初始化流程
1. 扫描阶段 - FeignClientsRegistrar
关键代码 (FeignClientsRegistrar.registerBeanDefinitions
):
public void registerBeanDefinitions(...) {
// 扫描所有@FeignClient接口
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
// 为每个Feign客户端创建Bean定义
registerFeignClient(registry, annotationMetadata, attributes);
}
}
2. 创建 FeignClient 工厂 - FeignClientFactoryBean
每个 @FeignClient
接口都会关联一个 FeignClientFactoryBean
:
class FeignClientFactoryBean implements FactoryBean<Object> {
@Override
public Object getObject() {
return getTarget(); // 创建代理对象
}
protected <T> T getTarget() {
// 创建Feign.Builder
Feign.Builder builder = feign(context);
// 配置目标URL
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context,
Target.HardCodedTarget.create(type, name, url));
}
}
3. 构建 Feign 实例 - Feign.Builder
创建实际的 Feign 客户端:
protected Feign.Builder feign(FeignContext context) {
// 1. 获取基础组件
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
// 2. 配置契约(解析注解)
Contract contract = get(context, Contract.class);
// 3. 配置编码器/解码器
Encoder encoder = getOptional(context, Encoder.class);
Decoder decoder = getOptional(context, Decoder.class);
// 4. 创建Builder
Feign.Builder builder = get(context, Feign.Builder.class)
.logger(logger)
.encoder(encoder)
.decoder(decoder)
.contract(contract);
// 5. 配置拦截器
applyInterceptors(context, builder);
return builder;
}
4. 生成动态代理 - ReflectiveFeign
核心代理创建过程:
public class ReflectiveFeign extends Feign {
public <T> T newInstance(Target<T> target) {
// 创建方法映射
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<>();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) continue;
methodToHandler.put(method, createHandler(method, target));
}
// 创建动态代理
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(
target.type().getClassLoader(),
new Class<?>[] {target.type()},
handler);
return proxy;
}
}
5. 负载均衡集成 - LoadBalancerFeignClient
当使用 Ribbon 时,会创建负载均衡客户端:
class LoadBalancerFeignClient implements Client {
private final Client delegate;
private final LoadBalancerClient loadBalancer;
@Override
public Response execute(Request request, Request.Options options) {
// 解析服务名
final URI originalUri = URI.create(request.url());
String serviceId = originalUri.getHost();
// 通过负载均衡选择实例
ServiceInstance instance = loadBalancer.choose(serviceId);
URI uri = loadBalancer.reconstructURI(instance, originalUri);
// 创建新请求
Request newRequest = buildRequest(request, uri);
// 委托给底层客户端执行
return delegate.execute(newRequest, options);
}
}
总结
负载均衡核心步骤
Ribbon负载均衡核心步骤
服务发现:
从注册中心(如Eureka)拉取服务实例列表。策略选择:
根据配置的IRule实现类选择实例,默认策略为RoundRobinRule
(轮询)。请求转发:
将Feign请求中的服务名(如http://user-service/api
)替换为具体实例地址(如http://192.168.1.2:8080/api
)。
负载均衡策略配置
# 示例:配置随机策略
user-service: # 服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule