package com.xiaopeng.account.config; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.context.EnvironmentAware; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import java.util.Map; import java.util.Properties; /** * 修复 ShardingSphere 5.0.0 + Spring Boot 2.x 启动时 algorithm-expression 为 null 的问题。 * * 根因:算法名含下划线(如 xp_clock_in_inline),Spring Boot 2.x 的 Binder 在 * bind("...xp_clock_in_inline.props") 时抛 InvalidConfigurationPropertyNameException, * 导致 ShardingSphere 的 AbstractAlgorithmProvidedBeanRegistry 读取 props 失败。 * * 修复方式:通过顶层 Binder.bind(不含下划线路径段)获取完整算法配置, * 然后手动设置到对应 BeanDefinition 的 props 属性中。 * * 该修复对所有环境生效(本地 + Nacos),因为 Binder 下划线问题与配置来源无关。 */ @Component public class ShardingAlgorithmPropsFixer implements BeanFactoryPostProcessor, EnvironmentAware, Ordered { private static final String ALGO_PREFIX = "spring.shardingsphere.rules.sharding.sharding-algorithms"; private Environment environment; @Override public void setEnvironment(Environment environment) { this.environment = environment; } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } @Override @SuppressWarnings("unchecked") public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Map algorithms; try { algorithms = Binder.get(environment) .bind(ALGO_PREFIX, Map.class) .orElse(null); } catch (Exception e) { return; } if (algorithms == null) { return; } for (Map.Entry entry : algorithms.entrySet()) { String algoName = entry.getKey(); Object value = entry.getValue(); if (!(value instanceof Map)) { continue; } if (!beanFactory.containsBeanDefinition(algoName)) { continue; } Map algoConfig = (Map) value; Object propsObj = algoConfig.get("props"); if (!(propsObj instanceof Map)) { continue; } Map propsMap = (Map) propsObj; Properties props = new Properties(); for (Map.Entry pe : propsMap.entrySet()) { if (pe.getValue() != null) { props.put(pe.getKey(), pe.getValue().toString()); } } BeanDefinition bd = beanFactory.getBeanDefinition(algoName); bd.getPropertyValues().addPropertyValue("props", props); } } }