使用外部中间件时,如:金蝶、东方通 在不重启整个中间件的情况下,二次部署或多个服务同时部署在一个虚拟机下(JVM) IdTypeEnvironmentPostProcessor.setIdType 会将一个IdType对象put进SystemPropertiesPropertySource,而SystemPropertiesPropertySource在整个JVM中是共用的,导致两处问题:
报错信息:org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.baomidou.mybatisplus.annotation.IdType] to type [com.baomidou.mybatisplus.annotation.IdType] 问题一:IdTypeEnvironmentPostProcessor.getIdType 中 environment.getProperty(ID_TYPE_KEY, IdType.class) 获取到了上一次部署应用时的 IdType 对象,而上一次的 IdType 对象,和本次部署时 IdType.class 的类加载器不一致,导致报错; 问题二:org.springframework.boot.context.properties.bind.BindConverter.convert 中,delegate.canConvert 返回的都是false,最终:throw (failure != null) ? failure : new ConverterNotFoundException(sourceType, targetType); 原因分析: 首先 ConfigurableEnvironment ConfigurableEnvironment.getProperty(...) 的查找顺序是分层次的: 1、命令行参数(CommandLinePropertySource,即 --key=value) 2、Java 系统属性(System.getProperties(),对应 SystemPropertiesPropertySource) 3、操作系统环境变量(System.getenv(),对应 SystemEnvironmentPropertySource) 4、application.yml / application.properties(OriginTrackedMapPropertySource) 5、默认属性(DefaultPropertiesPropertySource) 其次:Spring 的属性绑定用到了 ConfigurationPropertySource ConfigurationPropertySource: 它是 Spring Boot 2.x 以后引入的抽象,表示配置属性的来源。 比如: .properties / .yml 文件, 系统属性(System.getProperties()), 环境变量(System.getenv()), 甚至 Nacos、Apollo 这样的远程配置中心。 它统一成 ConfigurationPropertySource 接口,Spring Boot 就能用同一套逻辑去读取配置。 和 ConfigurableEnvironment 的关系 ConfigurableEnvironment 内部持有一系列 PropertySource。 Spring Boot 启动时会把这些 PropertySource 适配成 ConfigurationPropertySource, 这样属性绑定器(Binder)就可以从中读取配置值。 也就是说: environment.getProperty("my.key") 读出来的值, 和 Binder 里 ConfigurationPropertySource 提供的值, 本质上是同一批配置源,只是走的 API 不一样。 导致的问题:org.springframework.boot.context.properties.bind.BindConverter.convert 的参数:Object source, TypeDescriptor sourceType, TypeDescriptor targetType source 是上一次部署时的 IdType 对象 sourceType 的类加载器 (sourceType.getType().getClassLoader()) 与 targetType 的类加载器 (targetType.getType().getClassLoader())不一致,抛出:ConverterNotFoundException org.springframework.boot.context.properties.bind.BindConverter.convert: private Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { ConversionException failure = null; for (ConversionService delegate : this.delegates) { try { if (delegate.canConvert(sourceType, targetType)) { return delegate.convert(source, sourceType, targetType); } } catch (ConversionException ex) { if (failure == null && ex instanceof ConversionFailedException) { failure = ex; } } } throw (failure != null) ? failure : new ConverterNotFoundException(sourceType, targetType); }pull/208/head
parent
21243b124c
commit
f12162e7ff
|
@ -9,7 +9,10 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -56,11 +59,23 @@ public class IdTypeEnvironmentPostProcessor implements EnvironmentPostProcessor
|
|||
}
|
||||
|
||||
public IdType getIdType(ConfigurableEnvironment environment) {
|
||||
return environment.getProperty(ID_TYPE_KEY, IdType.class);
|
||||
// return environment.getProperty(ID_TYPE_KEY, IdType.class);
|
||||
String value = environment.getProperty(ID_TYPE_KEY);
|
||||
try {
|
||||
return StrUtil.isNotBlank(value) ? IdType.valueOf(value) : IdType.NONE;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
log.error("无法解析 id-type 配置值:{}", value, ex);
|
||||
return IdType.NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setIdType(ConfigurableEnvironment environment, IdType idType) {
|
||||
environment.getSystemProperties().put(ID_TYPE_KEY, idType);
|
||||
// environment.getSystemProperties().put(ID_TYPE_KEY, idType);
|
||||
// log.info("[setIdType][修改 MyBatis Plus 的 idType 为({})]", idType);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ID_TYPE_KEY, idType);
|
||||
environment.getPropertySources().addFirst(new MapPropertySource("mybatisPlusIdType", map));
|
||||
log.info("[setIdType][修改 MyBatis Plus 的 idType 为({})]", idType);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue