From d302fb71f1d7ed0b0b5ecbb272529e1825350192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B7=E5=86=B7?= <2270033969@qq.com> Date: Thu, 4 Apr 2024 21:32:23 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=E9=87=8D=E6=9E=84=20feign?= =?UTF-8?q?=20=E5=AF=BC=E5=85=A5=E6=94=AF=E6=8C=81=E5=8D=95=E4=BD=93?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E9=80=9A=E8=BF=87SPI=20=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openfeign/PigFeignClientsRegistrar.java | 360 ++++++++++-------- 1 file changed, 195 insertions(+), 165 deletions(-) diff --git a/pig-common/pig-common-feign/src/main/java/org/springframework/cloud/openfeign/PigFeignClientsRegistrar.java b/pig-common/pig-common-feign/src/main/java/org/springframework/cloud/openfeign/PigFeignClientsRegistrar.java index 55d495c1..c34b4d81 100644 --- a/pig-common/pig-common-feign/src/main/java/org/springframework/cloud/openfeign/PigFeignClientsRegistrar.java +++ b/pig-common/pig-common-feign/src/main/java/org/springframework/cloud/openfeign/PigFeignClientsRegistrar.java @@ -34,6 +34,7 @@ import org.springframework.core.env.Environment; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.type.AnnotationMetadata; import org.springframework.lang.Nullable; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import java.util.ArrayList; @@ -48,199 +49,228 @@ import java.util.Map; */ public class PigFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware { - @Getter - private ClassLoader beanClassLoader; + private final static String BASE_URL = "http://127.0.0.1:${server.port}${server.servlet.context-path}"; - @Getter - private Environment environment; + @Getter + private ClassLoader beanClassLoader; - @Override - public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { - registerFeignClients(registry); - } + @Getter + private Environment environment; - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } + @Override + public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { + registerFeignClients(registry); + } - private void registerFeignClients(BeanDefinitionRegistry registry) { + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } - List feignClients = new ArrayList<>( - SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())); + private void registerFeignClients(BeanDefinitionRegistry registry) { + List feignClients = new ArrayList<>(); - // 支持 springboot 2.7 + 最新版本的配置方式 - ImportCandidates.load(FeignClient.class, getBeanClassLoader()).forEach(feignClients::add); - // 如果 spring.factories 里为空 - if (feignClients.isEmpty()) { - return; - } - for (String className : feignClients) { - try { - Class clazz = beanClassLoader.loadClass(className); - AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz, - FeignClient.class); - if (attributes == null) { - continue; - } - // 如果已经存在该 bean,支持原生的 Feign - if (registry.containsBeanDefinition(className)) { - continue; - } - registerClientConfiguration(registry, getClientName(attributes), attributes.get("configuration")); + // 支持 springboot 2.7 + 最新版本的配置方式 + ImportCandidates.load(FeignClient.class, getBeanClassLoader()).forEach(feignClients::add); - validate(attributes); - BeanDefinitionBuilder definition = BeanDefinitionBuilder - .genericBeanDefinition(FeignClientFactoryBean.class); - definition.addPropertyValue("url", getUrl(attributes)); - definition.addPropertyValue("path", getPath(attributes)); - String name = getName(attributes); - definition.addPropertyValue("name", name); + // 如果 spring.factories 里为空 + if (feignClients.isEmpty()) { + return; + } + for (String className : feignClients) { + try { + Class clazz = beanClassLoader.loadClass(className); + AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz, + FeignClient.class); + if (attributes == null) { + continue; + } - // 兼容最新版本的 spring-cloud-openfeign,尚未发布 - StringBuilder aliasBuilder = new StringBuilder(18); - if (attributes.containsKey("contextId")) { - String contextId = getContextId(attributes); - aliasBuilder.append(contextId); - definition.addPropertyValue("contextId", contextId); - } - else { - aliasBuilder.append(name); - } + // 如果是单体项目自动注入 & url 为空 + Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true); + // 如果已经存在该 bean,支持原生的 Feign + if (registry.containsBeanDefinition(className) && isMicro) { + continue; + } - definition.addPropertyValue("type", className); - definition.addPropertyValue("decode404", attributes.get("decode404")); - definition.addPropertyValue("fallback", attributes.get("fallback")); - definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); - definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); + registerClientConfiguration(registry, getClientName(attributes), className, + attributes.get("configuration")); - AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); + validate(attributes); + BeanDefinitionBuilder definition = BeanDefinitionBuilder + .genericBeanDefinition(FeignClientFactoryBean.class); + definition.addPropertyValue("url", getUrl(registry, attributes)); + definition.addPropertyValue("path", getPath(attributes)); + String name = getName(attributes); + definition.addPropertyValue("name", name); - // alias - String alias = aliasBuilder.append("FeignClient").toString(); + // 兼容最新版本的 spring-cloud-openfeign,尚未发布 + StringBuilder aliasBuilder = new StringBuilder(18); + if (attributes.containsKey("contextId")) { + String contextId = getContextId(attributes); + aliasBuilder.append(contextId); + definition.addPropertyValue("contextId", contextId); + } else { + aliasBuilder.append(name); + } - // has a default, won't be null - boolean primary = (Boolean) attributes.get("primary"); + definition.addPropertyValue("type", className); + definition.addPropertyValue("dismiss404", + Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404")))); + Object fallbackFactory = attributes.get("fallbackFactory"); + if (fallbackFactory != null) { + definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory + : ClassUtils.resolveClassName(fallbackFactory.toString(), null)); + } + definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); + definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); - beanDefinition.setPrimary(primary); + AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); - String qualifier = getQualifier(attributes); - if (StringUtils.hasText(qualifier)) { - alias = qualifier; - } + // alias + String alias = aliasBuilder.append("FeignClient").toString(); - BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, - new String[] { alias }); - BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); + // has a default, won't be null + boolean primary = (Boolean) attributes.get("primary"); - } - catch (ClassNotFoundException e) { - e.printStackTrace(); - } - } - } + beanDefinition.setPrimary(primary); - /** - * Return the class used by {@link SpringFactoriesLoader} to load configuration - * candidates. - * @return the factory class - */ - private Class getSpringFactoriesLoaderFactoryClass() { - return PigFeignAutoConfiguration.class; - } + String qualifier = getQualifier(attributes); + if (StringUtils.hasText(qualifier)) { + alias = qualifier; + } - private void validate(Map attributes) { - AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes); - // This blows up if an aliased property is overspecified - FeignClientsRegistrar.validateFallback(annotation.getClass("fallback")); - FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory")); - } + BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, + new String[]{alias}); + BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); - private String getName(Map attributes) { - String name = (String) attributes.get("serviceId"); - if (!StringUtils.hasText(name)) { - name = (String) attributes.get("name"); - } - if (!StringUtils.hasText(name)) { - name = (String) attributes.get("value"); - } - name = resolve(name); - return FeignClientsRegistrar.getName(name); - } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + } - private String getContextId(Map attributes) { - String contextId = (String) attributes.get("contextId"); - if (!StringUtils.hasText(contextId)) { - return getName(attributes); - } + /** + * Return the class used by {@link SpringFactoriesLoader} to load configuration + * candidates. + * + * @return the factory class + */ + private Class getSpringFactoriesLoaderFactoryClass() { + return PigFeignAutoConfiguration.class; + } - contextId = resolve(contextId); - return FeignClientsRegistrar.getName(contextId); - } + private void validate(Map attributes) { + AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes); + // This blows up if an aliased property is overspecified + FeignClientsRegistrar.validateFallback(annotation.getClass("fallback")); + FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory")); + } - private String resolve(String value) { - if (StringUtils.hasText(value)) { - return this.environment.resolvePlaceholders(value); - } - return value; - } + private String getName(Map attributes) { + String name = (String) attributes.get("serviceId"); + if (!StringUtils.hasText(name)) { + name = (String) attributes.get("name"); + } + if (!StringUtils.hasText(name)) { + name = (String) attributes.get("value"); + } + name = resolve(name); + return FeignClientsRegistrar.getName(name); + } - private String getUrl(Map attributes) { - String url = resolve((String) attributes.get("url")); - return FeignClientsRegistrar.getUrl(url); - } + private String getContextId(Map attributes) { + String contextId = (String) attributes.get("contextId"); + if (!StringUtils.hasText(contextId)) { + return getName(attributes); + } - private String getPath(Map attributes) { - String path = resolve((String) attributes.get("path")); - return FeignClientsRegistrar.getPath(path); - } + contextId = resolve(contextId); + return FeignClientsRegistrar.getName(contextId); + } - @Nullable - private String getQualifier(@Nullable Map client) { - if (client == null) { - return null; - } - String qualifier = (String) client.get("qualifier"); - if (StringUtils.hasText(qualifier)) { - return qualifier; - } - return null; - } + private String resolve(String value) { + if (StringUtils.hasText(value)) { + return this.environment.resolvePlaceholders(value); + } + return value; + } - @Nullable - private String getClientName(@Nullable Map client) { - if (client == null) { - return null; - } - String value = (String) client.get("contextId"); - if (!StringUtils.hasText(value)) { - value = (String) client.get("value"); - } - if (!StringUtils.hasText(value)) { - value = (String) client.get("name"); - } - if (!StringUtils.hasText(value)) { - value = (String) client.get("serviceId"); - } - if (StringUtils.hasText(value)) { - return value; - } + private String getUrl(BeanDefinitionRegistry registry, Map attributes) { - throw new IllegalStateException( - "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName()); - } + // 如果是单体项目自动注入 & url 为空 + Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true); - private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); - builder.addConstructorArgValue(name); - builder.addConstructorArgValue(configuration); - registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), - builder.getBeanDefinition()); - } + if (isMicro) { + return null; + } - @Override - public void setEnvironment(Environment environment) { - this.environment = environment; - } + String url = resolve(BASE_URL); + + return FeignClientsRegistrar.getUrl(url); + } + + private String getPath(Map attributes) { + String path = resolve((String) attributes.get("path")); + return FeignClientsRegistrar.getPath(path); + } + + @Nullable + private String getQualifier(@Nullable Map client) { + if (client == null) { + return null; + } + String qualifier = (String) client.get("qualifier"); + if (StringUtils.hasText(qualifier)) { + return qualifier; + } + return null; + } + + @Nullable + private String getClientName(@Nullable Map client) { + if (client == null) { + return null; + } + String value = (String) client.get("contextId"); + if (!StringUtils.hasText(value)) { + value = (String) client.get("value"); + } + if (!StringUtils.hasText(value)) { + value = (String) client.get("name"); + } + if (!StringUtils.hasText(value)) { + value = (String) client.get("serviceId"); + } + if (StringUtils.hasText(value)) { + return value; + } + + throw new IllegalStateException( + "Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName()); + } + + private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); + builder.addConstructorArgValue(name); + builder.addConstructorArgValue(configuration); + registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), + builder.getBeanDefinition()); + } + + private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object className, + Object configuration) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class); + builder.addConstructorArgValue(name); + builder.addConstructorArgValue(className); + builder.addConstructorArgValue(configuration); + registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), + builder.getBeanDefinition()); + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } }