|
59 | 59 | import org.springframework.util.StringUtils; |
60 | 60 |
|
61 | 61 | /** |
| 62 | + * A {@link FactoryBean} responsible for creating Feign client proxies. |
| 63 | + * |
| 64 | + * <p><strong>Note:</strong> Custom {@link Client} beans provided in a Feign client |
| 65 | + * context should be singleton-scoped. Defining a prototype-scoped {@code Client} |
| 66 | + * may lead to multiple underlying HTTP connection pools being created, which |
| 67 | + * can result in resource exhaustion. |
| 68 | + * |
| 69 | + * @author Spencer Gibb |
| 70 | + * @author Venil Noronha |
| 71 | + * @author Eko Kurniawan Khannedy |
| 72 | + * @author Gregor Zurowski |
| 73 | + * @author Matt King |
| 74 | + * @author Olga Maciaszek-Sharma |
| 75 | + * @author Ilia Ilinykh |
| 76 | + * @author Marcin Grzejszczak |
| 77 | + * @author Jonatan Ivanov |
| 78 | + * @author Sam Kruglov |
| 79 | + * @author Jasbir Singh |
| 80 | + * @author Hyeonmin Park |
| 81 | + * @author Felix Dittrich |
| 82 | + * @author Dominique Villard |
| 83 | + * @author Can Bezmen |
| 84 | + */ |
| 85 | +/** |
| 86 | + * A {@link FactoryBean} responsible for creating Feign client proxies. |
| 87 | + * |
| 88 | + * <p> |
| 89 | + * <strong>Note:</strong> Custom {@link Client} beans provided in a Feign client context |
| 90 | + * should be singleton-scoped. Defining a prototype-scoped {@code Client} may lead to |
| 91 | + * multiple underlying HTTP connection pools being created, which can result in resource |
| 92 | + * exhaustion. |
| 93 | + * |
62 | 94 | * @author Spencer Gibb |
63 | 95 | * @author Venil Noronha |
64 | 96 | * @author Eko Kurniawan Khannedy |
@@ -465,42 +497,64 @@ public Object getObject() { |
465 | 497 | <T> T getTarget() { |
466 | 498 | FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class) |
467 | 499 | : applicationContext.getBean(FeignClientFactory.class); |
| 500 | + |
468 | 501 | Feign.Builder builder = feign(feignClientFactory); |
| 502 | + |
469 | 503 | if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) { |
470 | 504 |
|
471 | 505 | if (LOG.isInfoEnabled()) { |
472 | 506 | LOG.info("For '" + name + "' URL not provided. Will try picking an instance via load-balancing."); |
473 | 507 | } |
| 508 | + |
474 | 509 | if (!name.startsWith("http://") && !name.startsWith("https://")) { |
475 | 510 | url = "http://" + name; |
476 | 511 | } |
477 | 512 | else { |
478 | 513 | url = name; |
479 | 514 | } |
| 515 | + |
480 | 516 | url += cleanPath(); |
481 | 517 | return (T) loadBalance(builder, feignClientFactory, new HardCodedTarget<>(type, name, url)); |
482 | 518 | } |
| 519 | + |
483 | 520 | if (StringUtils.hasText(url) && !url.startsWith("http://") && !url.startsWith("https://")) { |
484 | 521 | url = "http://" + url; |
485 | 522 | } |
| 523 | + |
486 | 524 | Client client = getOptional(feignClientFactory, Client.class); |
| 525 | + |
487 | 526 | if (client != null) { |
| 527 | + |
| 528 | + try { |
| 529 | + Map<String, Client> clients = feignClientFactory.getInstances(contextId, Client.class); |
| 530 | + |
| 531 | + if (clients != null && clients.size() > 1) { |
| 532 | + LOG.warn("Multiple Feign Client beans detected for contextId '" + contextId |
| 533 | + + "'. Custom Client beans should typically be singleton-scoped " |
| 534 | + + "to avoid multiple underlying connection pools."); |
| 535 | + } |
| 536 | + } |
| 537 | + catch (Exception ex) { |
| 538 | + if (LOG.isDebugEnabled()) { |
| 539 | + LOG.debug("Unable to inspect Feign Client beans for contextId '" + contextId + "'", ex); |
| 540 | + } |
| 541 | + } |
| 542 | + |
488 | 543 | if (client instanceof FeignBlockingLoadBalancerClient) { |
489 | | - // not load balancing because we have a url, |
490 | | - // but Spring Cloud LoadBalancer is on the classpath, so unwrap |
491 | 544 | client = ((FeignBlockingLoadBalancerClient) client).getDelegate(); |
492 | 545 | } |
| 546 | + |
493 | 547 | if (client instanceof RetryableFeignBlockingLoadBalancerClient) { |
494 | | - // not load balancing because we have a url, |
495 | | - // but Spring Cloud LoadBalancer is on the classpath, so unwrap |
496 | 548 | client = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate(); |
497 | 549 | } |
| 550 | + |
498 | 551 | builder.client(client); |
499 | 552 | } |
500 | 553 |
|
501 | 554 | applyBuildCustomizers(feignClientFactory, builder); |
502 | 555 |
|
503 | 556 | Targeter targeter = get(feignClientFactory, Targeter.class); |
| 557 | + |
504 | 558 | return targeter.target(this, builder, feignClientFactory, resolveTarget(feignClientFactory, contextId, url)); |
505 | 559 | } |
506 | 560 |
|
|
0 commit comments