mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-23 05:00:23 +08:00
♻️ 重构 feign 导入支持单体版本通过SPI 导入
This commit is contained in:
parent
1af0c068b0
commit
d302fb71f1
@ -34,6 +34,7 @@ import org.springframework.core.env.Environment;
|
|||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -48,199 +49,228 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class PigFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
|
public class PigFeignClientsRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware, EnvironmentAware {
|
||||||
|
|
||||||
@Getter
|
private final static String BASE_URL = "http://127.0.0.1:${server.port}${server.servlet.context-path}";
|
||||||
private ClassLoader beanClassLoader;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private Environment environment;
|
private ClassLoader beanClassLoader;
|
||||||
|
|
||||||
@Override
|
@Getter
|
||||||
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
|
private Environment environment;
|
||||||
registerFeignClients(registry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
|
||||||
this.beanClassLoader = classLoader;
|
registerFeignClients(registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerFeignClients(BeanDefinitionRegistry registry) {
|
@Override
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
this.beanClassLoader = classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
List<String> feignClients = new ArrayList<>(
|
private void registerFeignClients(BeanDefinitionRegistry registry) {
|
||||||
SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()));
|
List<String> feignClients = new ArrayList<>();
|
||||||
|
|
||||||
// 支持 springboot 2.7 + 最新版本的配置方式
|
// 支持 springboot 2.7 + 最新版本的配置方式
|
||||||
ImportCandidates.load(FeignClient.class, getBeanClassLoader()).forEach(feignClients::add);
|
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"));
|
|
||||||
|
|
||||||
validate(attributes);
|
// 如果 spring.factories 里为空
|
||||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder
|
if (feignClients.isEmpty()) {
|
||||||
.genericBeanDefinition(FeignClientFactoryBean.class);
|
return;
|
||||||
definition.addPropertyValue("url", getUrl(attributes));
|
}
|
||||||
definition.addPropertyValue("path", getPath(attributes));
|
for (String className : feignClients) {
|
||||||
String name = getName(attributes);
|
try {
|
||||||
definition.addPropertyValue("name", name);
|
Class<?> clazz = beanClassLoader.loadClass(className);
|
||||||
|
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(clazz,
|
||||||
|
FeignClient.class);
|
||||||
|
if (attributes == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 兼容最新版本的 spring-cloud-openfeign,尚未发布
|
// 如果是单体项目自动注入 & url 为空
|
||||||
StringBuilder aliasBuilder = new StringBuilder(18);
|
Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
|
||||||
if (attributes.containsKey("contextId")) {
|
// 如果已经存在该 bean,支持原生的 Feign
|
||||||
String contextId = getContextId(attributes);
|
if (registry.containsBeanDefinition(className) && isMicro) {
|
||||||
aliasBuilder.append(contextId);
|
continue;
|
||||||
definition.addPropertyValue("contextId", contextId);
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
aliasBuilder.append(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
definition.addPropertyValue("type", className);
|
registerClientConfiguration(registry, getClientName(attributes), className,
|
||||||
definition.addPropertyValue("decode404", attributes.get("decode404"));
|
attributes.get("configuration"));
|
||||||
definition.addPropertyValue("fallback", attributes.get("fallback"));
|
|
||||||
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
|
|
||||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
|
||||||
|
|
||||||
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
|
// 兼容最新版本的 spring-cloud-openfeign,尚未发布
|
||||||
String alias = aliasBuilder.append("FeignClient").toString();
|
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
|
definition.addPropertyValue("type", className);
|
||||||
boolean primary = (Boolean) attributes.get("primary");
|
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);
|
// alias
|
||||||
if (StringUtils.hasText(qualifier)) {
|
String alias = aliasBuilder.append("FeignClient").toString();
|
||||||
alias = qualifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
|
// has a default, won't be null
|
||||||
new String[] { alias });
|
boolean primary = (Boolean) attributes.get("primary");
|
||||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
|
|
||||||
|
|
||||||
}
|
beanDefinition.setPrimary(primary);
|
||||||
catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
String qualifier = getQualifier(attributes);
|
||||||
* Return the class used by {@link SpringFactoriesLoader} to load configuration
|
if (StringUtils.hasText(qualifier)) {
|
||||||
* candidates.
|
alias = qualifier;
|
||||||
* @return the factory class
|
}
|
||||||
*/
|
|
||||||
private Class<?> getSpringFactoriesLoaderFactoryClass() {
|
|
||||||
return PigFeignAutoConfiguration.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validate(Map<String, Object> attributes) {
|
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
|
||||||
AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
|
new String[]{alias});
|
||||||
// This blows up if an aliased property is overspecified
|
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
|
||||||
FeignClientsRegistrar.validateFallback(annotation.getClass("fallback"));
|
|
||||||
FeignClientsRegistrar.validateFallbackFactory(annotation.getClass("fallbackFactory"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getName(Map<String, Object> attributes) {
|
} catch (ClassNotFoundException e) {
|
||||||
String name = (String) attributes.get("serviceId");
|
e.printStackTrace();
|
||||||
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<String, Object> attributes) {
|
/**
|
||||||
String contextId = (String) attributes.get("contextId");
|
* Return the class used by {@link SpringFactoriesLoader} to load configuration
|
||||||
if (!StringUtils.hasText(contextId)) {
|
* candidates.
|
||||||
return getName(attributes);
|
*
|
||||||
}
|
* @return the factory class
|
||||||
|
*/
|
||||||
|
private Class<?> getSpringFactoriesLoaderFactoryClass() {
|
||||||
|
return PigFeignAutoConfiguration.class;
|
||||||
|
}
|
||||||
|
|
||||||
contextId = resolve(contextId);
|
private void validate(Map<String, Object> attributes) {
|
||||||
return FeignClientsRegistrar.getName(contextId);
|
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) {
|
private String getName(Map<String, Object> attributes) {
|
||||||
if (StringUtils.hasText(value)) {
|
String name = (String) attributes.get("serviceId");
|
||||||
return this.environment.resolvePlaceholders(value);
|
if (!StringUtils.hasText(name)) {
|
||||||
}
|
name = (String) attributes.get("name");
|
||||||
return value;
|
}
|
||||||
}
|
if (!StringUtils.hasText(name)) {
|
||||||
|
name = (String) attributes.get("value");
|
||||||
|
}
|
||||||
|
name = resolve(name);
|
||||||
|
return FeignClientsRegistrar.getName(name);
|
||||||
|
}
|
||||||
|
|
||||||
private String getUrl(Map<String, Object> attributes) {
|
private String getContextId(Map<String, Object> attributes) {
|
||||||
String url = resolve((String) attributes.get("url"));
|
String contextId = (String) attributes.get("contextId");
|
||||||
return FeignClientsRegistrar.getUrl(url);
|
if (!StringUtils.hasText(contextId)) {
|
||||||
}
|
return getName(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
private String getPath(Map<String, Object> attributes) {
|
contextId = resolve(contextId);
|
||||||
String path = resolve((String) attributes.get("path"));
|
return FeignClientsRegistrar.getName(contextId);
|
||||||
return FeignClientsRegistrar.getPath(path);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
private String resolve(String value) {
|
||||||
private String getQualifier(@Nullable Map<String, Object> client) {
|
if (StringUtils.hasText(value)) {
|
||||||
if (client == null) {
|
return this.environment.resolvePlaceholders(value);
|
||||||
return null;
|
}
|
||||||
}
|
return value;
|
||||||
String qualifier = (String) client.get("qualifier");
|
}
|
||||||
if (StringUtils.hasText(qualifier)) {
|
|
||||||
return qualifier;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
private String getUrl(BeanDefinitionRegistry registry, Map<String, Object> attributes) {
|
||||||
private String getClientName(@Nullable Map<String, Object> 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(
|
// 如果是单体项目自动注入 & url 为空
|
||||||
"Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());
|
Boolean isMicro = environment.getProperty("spring.cloud.nacos.discovery.enabled", Boolean.class, true);
|
||||||
}
|
|
||||||
|
|
||||||
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
|
if (isMicro) {
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
|
return null;
|
||||||
builder.addConstructorArgValue(name);
|
}
|
||||||
builder.addConstructorArgValue(configuration);
|
|
||||||
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),
|
|
||||||
builder.getBeanDefinition());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
String url = resolve(BASE_URL);
|
||||||
public void setEnvironment(Environment environment) {
|
|
||||||
this.environment = environment;
|
return FeignClientsRegistrar.getUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getPath(Map<String, Object> attributes) {
|
||||||
|
String path = resolve((String) attributes.get("path"));
|
||||||
|
return FeignClientsRegistrar.getPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String getQualifier(@Nullable Map<String, Object> 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<String, Object> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user