diff --git a/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/PigxFeignAutoConfiguration.java b/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/PigxFeignAutoConfiguration.java
index 6a4ca5641..db0f54436 100644
--- a/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/PigxFeignAutoConfiguration.java
+++ b/pigx-common/pigx-common-feign/src/main/java/com/pig4cloud/pigx/common/feign/PigxFeignAutoConfiguration.java
@@ -24,9 +24,11 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.PigxFeignClientsRegistrar;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
/**
* @author lengleng
@@ -36,6 +38,7 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@ConditionalOnClass(Feign.class)
+@Import(PigxFeignClientsRegistrar.class)
@AutoConfigureAfter(EnableFeignClients.class)
public class PigxFeignAutoConfiguration {
diff --git a/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java b/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java
new file mode 100644
index 000000000..eea83315b
--- /dev/null
+++ b/pigx-common/pigx-common-feign/src/main/java/org/springframework/cloud/openfeign/PigxFeignClientsRegistrar.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2018-2025, lengleng All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the pig4cloud.com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: lengleng (wangiegie@gmail.com)
+ */
+
+package org.springframework.cloud.openfeign;
+
+import com.pig4cloud.pigx.common.feign.PigxFeignAutoConfiguration;
+import lombok.Getter;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.boot.context.annotation.ImportCandidates;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationAttributes;
+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.List;
+import java.util.Map;
+
+/**
+ * @author L.cm
+ * @date 2020/2/8
+ *
+ * feign 自动配置功能 from mica
+ */
+public class PigxFeignClientsRegistrar
+ implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
+
+ private final static String BASE_URL = "http://127.0.0.1:${server.port}${server.servlet.context-path}";
+
+ @Getter
+ private ClassLoader beanClassLoader;
+
+ @Getter
+ private Environment environment;
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
+ registerFeignClients(registry);
+ }
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+
+ private void registerFeignClients(BeanDefinitionRegistry registry) {
+ List feignClients = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
+ getBeanClassLoader());
+
+ // 支持 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), className, attributes.get("configuration"));
+
+ 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-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);
+ }
+
+ 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);
+
+ AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
+
+ // alias
+ String alias = aliasBuilder.append("FeignClient").toString();
+
+ // has a default, won't be null
+ boolean primary = (Boolean) attributes.get("primary");
+
+ beanDefinition.setPrimary(primary);
+
+ String qualifier = getQualifier(attributes);
+ if (StringUtils.hasText(qualifier)) {
+ alias = qualifier;
+ }
+
+ BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
+ new String[] { alias });
+ BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
+
+ }
+ catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Return the class used by {@link SpringFactoriesLoader} to load configuration
+ * candidates.
+ * @return the factory class
+ */
+ private Class> getSpringFactoriesLoaderFactoryClass() {
+ return PigxFeignAutoConfiguration.class;
+ }
+
+ 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 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 getContextId(Map attributes) {
+ String contextId = (String) attributes.get("contextId");
+ if (!StringUtils.hasText(contextId)) {
+ return getName(attributes);
+ }
+
+ contextId = resolve(contextId);
+ return FeignClientsRegistrar.getName(contextId);
+ }
+
+ private String resolve(String value) {
+ if (StringUtils.hasText(value)) {
+ return this.environment.resolvePlaceholders(value);
+ }
+ return value;
+ }
+
+ private String getUrl(Map attributes) {
+ // 如果是单体项目自动注入 & url 为空
+ String url = (String) attributes.get("url");
+ boolean present = ClassUtils.isPresent("com.alibaba.cloud.nacos.discovery.NacosDiscoveryClient",
+ this.getClass().getClassLoader());
+ if (!StringUtils.hasText(url) && !present) {
+ 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;
+ }
+
+}
diff --git a/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..460350b55
--- /dev/null
+++ b/pigx-upms/pigx-upms-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,9 @@
+com.pig4cloud.pigx.admin.api.feign.RemoteDataScopeService
+com.pig4cloud.pigx.admin.api.feign.RemoteClientDetailsService
+com.pig4cloud.pigx.admin.api.feign.RemoteLogService
+com.pig4cloud.pigx.admin.api.feign.RemoteParamService
+com.pig4cloud.pigx.admin.api.feign.RemoteTenantService
+com.pig4cloud.pigx.admin.api.feign.RemoteTokenService
+com.pig4cloud.pigx.admin.api.feign.RemoteUserService
+com.pig4cloud.pigx.admin.api.feign.RemoteDictService
+com.pig4cloud.pigx.admin.api.feign.RemoteAuditLogService