@Service("lecOrderService")
public class LecOrderServiceImpl extends ServiceImpl<LecOrderDao, LecOrderEntity> implements LecOrderService {
@Autowired //自动注入依赖
SeckillFeignService seckillFeignService;
上述Service的Bean加载过程中,发现存在了这么个依赖,那不得去处理下,参考单例Bean的加载。
他这个优秀,缓存中直接就有了,在启动时通过@EnableFeignClients(basePackages = “com.yfxu.lecture.product.feign”) 将所有带有@FeignClient(“lecture-seckill”)的对应SeckillFeignService已经作为FeignClientFactoryBean进入IOC
populateBean()解析并自动注入依赖-> getBean("com.yfxu.lecture.product.feign.SeckillFeignService")
-> 寻思从FeignClientFactoryBean#getObject()取出依赖的对象
只不过这里有些不一样,来看FeignClientFactoryBean的具体实现
@Override
public Object getObject() throws Exception {
return getTarget(); //拿到上下文 并配置拦截器
}
最终会执行Feign中的下面方法
在ReflectiveFeign中绑定seckillFeignService的统一InvocationHandler处理的动态代理
触发代理调用
R r1 = seckillFeignService.getSeckillInfoByActId(relationEntity.getActId());
//统一的方法拦截器
static class FeignInvocationHandler implements InvocationHandler {
...
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
//触发每个方法的SynchronousMethodHandler拦截器
return dispatch.get(method).invoke(args);
}
feign/SynchronousMethodHandler.java:89
final class SynchronousMethodHandler implements MethodHandler {
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv); //根据输入参数为每个请求简历一个请求template
Options options = findOptions(argv);
Retryer retryer = this.retryer.clone(); //克隆一份重试器
while (true) { //失败重试机制,尝试一定次数
try {
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
...
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
Request request = targetRequest(template); //调用请求拦截器 生成request
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
response = client.execute(request, options); //由客户端LoadBalancerFeignClient执行对服务器的请求
// ensure the request is set. TODO: remove in Feign 12
response = response.toBuilder()
.request(request)
.requestTemplate(template)
.build();
} catch (IOException e) {
...
Request targetRequest(RequestTemplate template) {
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
return target.apply(template);
}
Client组件
其中Client组件是一个非常重要的组件,Feign最终发送request请求以及接收response响应,都是由Client组件完成的,其中Client的实现类,只要有Client.Default,该类由HttpURLConnnection实现网络请求,另外还支持HttpClient、Okhttp.
在缺失配置feignClient的情况下,会自动注入new Client.Default(),跟踪Client.Default()源码,它使用的网络请求框架为HttpURLConnection,代码如下:
@Override
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = convertAndSend(request, options);
return convertResponse(connection, request);
}
但HttpURLConnection没有连接池,对每个地址会保持一个长连接,所以建议配置HttpClient、Okhttp客户端
参考link
负载均衡请求
通过上述的FeignRibbonClientAutoConfiguration类配置Client的类型(httpurlconnection,okhttp和httpclient)时候,可知最终向容器注入的是LoadBalancerFeignClient,即负载均衡客户端。现在来看下LoadBalancerFeignClient的代码:
openfeign/ribbon/LoadBalancerFeignClient.java:74
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
IClientConfig requestConfig = getClientConfig(options, clientName);
return lbClient(clientName)
.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
}
1.通过lbClient(clientName)生成FeignLoadBalancer类。主要借助Nacos注册中心的服务列表
DynamicServerListLoadBalancer:{NFLoadBalancer:name=lecture-seckill,current list of Servers=[192.168.101.48:12000],Load balancer stats=Zone stats: {unknown=[Zone:unknown; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:192.168.101.48:12000; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:com.alibaba.cloud.nacos.ribbon.NacosServerList@72d5b022
2.其中有个executeWithLoadBalancer()方法,即通过负载均衡的方式请求。
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, requestConfig);
LoadBalancerCommand<T> command = LoadBalancerCommand.<T>builder()
.withLoadBalancerContext(this)
.withRetryHandler(handler)
.withLoadBalancerURI(request.getUri())
.build();
try {
return command.submit(
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
URI finalUri = reconstructURIWithServer(server, request.getUri());
S requestForServer = (S) request.replaceUri(finalUri);
try {
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
catch (Exception e) {
return Observable.error(e);
}
}
})
.toBlocking()
.single();
} catch (Exception e) {
其中服务在submit()方法上,点击submit进入具体的方法,这个方法是LoadBalancerCommand的方法:
Observable<T> o = (this.server == null ? this.selectServer() : Observable.just(this.server)).concatMap(new Func1<Server, Observable<T>>() {
public Observable<T> call(Server server) {
context.setServer(server);
上述代码中有个selectServe(),该方法是选择服务的进行负载均衡的方法,代码如下:
private Observable<Server> selectServer() {
return Observable.create(new OnSubscribe<Server>() {
public void call(Subscriber<? super Server> next) {
try {
Server server = LoadBalancerCommand.this.loadBalancerContext.getServerFromLoadBalancer(LoadBalancerCommand.this.loadBalancerURI, LoadBalancerCommand.this.loadBalancerKey);
next.onNext(server);
next.onCompleted();
} catch (Exception var3) {
next.onError(var3);
}
}
});
}
这篇博文写的也还不错:link