package link.at17.mid.tushare.component; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.DependsOn; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter; import link.at17.mid.tushare.annotation.ConfigInfo; import link.at17.mid.tushare.interfaces.IConfig; import lombok.extern.slf4j.Slf4j; /** * 实现自动化注册 Config */ @Slf4j @DependsOn("configService") public class ConfigAutoRegistrar implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AssignableTypeFilter(IConfig.class)); scanner.addIncludeFilter(new AnnotationTypeFilter(ConfigInfo.class)); scanner.findCandidateComponents("link.at17.mid.tushare.system.config").forEach(beanDefinition -> { String className = beanDefinition.getBeanClassName(); try { // 确保其 field 规则与 configService 内 field 生成规则一致,即: // 如果 @ConfigInfo 指定了 field 的,使用该 field + "Config" // 作为 beanName,否则使用首字母小写的 simpleClassName 作为 // beanName,且 simpleClassName 无论如何必须以 Config 作为结尾。 Class clazz = Class.forName(className); String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1); if (!IConfig.class.isAssignableFrom(clazz)) { log.warn("Config {} does not implement IConfig, ignore", beanName); return; } if (!beanName.endsWith("Config")) { log.warn("Config {}'s simple class name does not end with \"Config\", ignore", beanName); return; } ConfigInfo info = clazz.getAnnotation(ConfigInfo.class); if (info == null) { log.warn("Config {} does not have @ConfigInfo annotation, ignore", clazz.getName()); return; } if (StringUtils.isNotBlank(info.field())) { beanName = info.field() + "Config"; } BeanDefinitionBuilder factoryBean = BeanDefinitionBuilder .genericBeanDefinition(ConfigServiceFactoryBean.class) .addConstructorArgValue(clazz); // 注意此处注册 factoryBean 不意味着 FactoryBean.getObject() 方法立即被执行, // Spring 管理的 Bean 默认在其被使用时才创建,所以如果 getObject() 调用一些方 // 法,这些方法会在初次使用 Bean 时才被创建。如果这些方法对于启动过程很重要, // 需要在对应 Config(Bean) 上加上 @Bean 和 @Lazy(false) 注解,确保一旦准备好 // 相应的 Bean 就会被创建。 registry.registerBeanDefinition(beanName, factoryBean.getBeanDefinition()); log.info("Add config {} to bean register", beanName); } catch (ClassNotFoundException e) { throw new RuntimeException("Failed to load class: " + className, e); } }); } }