当前位置: 首页 > news >正文

Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.1 Spring Boot自动配置

👋 大家好,我是 阿问学长!专注于分享优质开源项目解析、毕业设计项目指导支持、幼小初高教辅资料推荐等,欢迎关注交流!🚀

Spring Boot自动配置

前言

Spring Boot的自动配置是其核心特性之一,通过约定优于配置的理念,大大简化了Spring应用的配置工作。RuoYi-Vue-Plus框架充分利用了Spring Boot的自动配置机制,同时也提供了大量自定义的自动配置类。本文将深入解析Spring Boot自动配置的原理、@Configuration配置类的使用、@ConditionalOn条件注解的应用,以及如何开发自定义Starter等内容。

@Configuration配置类

基础配置类

/*** 系统基础配置类*/
@Configuration
@EnableConfigurationProperties({SystemProperties.class, SecurityProperties.class})
@ConditionalOnProperty(prefix = "system", name = "enabled", havingValue = "true", matchIfMissing = true)
public class SystemAutoConfiguration {private static final Logger log = LoggerFactory.getLogger(SystemAutoConfiguration.class);@Autowiredprivate SystemProperties systemProperties;@Autowiredprivate SecurityProperties securityProperties;/*** 系统工具类配置*/@Bean@ConditionalOnMissingBeanpublic SystemUtils systemUtils() {log.info("初始化系统工具类");return new SystemUtils(systemProperties);}/*** 系统监控配置*/@Bean@ConditionalOnProperty(prefix = "system.monitor", name = "enabled", havingValue = "true")public SystemMonitor systemMonitor() {log.info("初始化系统监控");SystemMonitor monitor = new SystemMonitor();monitor.setEnabled(systemProperties.getMonitor().isEnabled());monitor.setInterval(systemProperties.getMonitor().getInterval());return monitor;}/*** 系统缓存配置*/@Bean@ConditionalOnClass(RedisTemplate.class)@ConditionalOnProperty(prefix = "system.cache", name = "type", havingValue = "redis")public SystemCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate) {log.info("初始化Redis缓存管理器");return new RedisCacheManager(redisTemplate, systemProperties.getCache());}/*** 本地缓存配置*/@Bean@ConditionalOnMissingBean(SystemCacheManager.class)@ConditionalOnProperty(prefix = "system.cache", name = "type", havingValue = "local", matchIfMissing = true)public SystemCacheManager localCacheManager() {log.info("初始化本地缓存管理器");return new LocalCacheManager(systemProperties.getCache());}/*** 系统事件发布器*/@Bean@ConditionalOnMissingBeanpublic SystemEventPublisher systemEventPublisher(ApplicationEventPublisher eventPublisher) {log.info("初始化系统事件发布器");return new SystemEventPublisher(eventPublisher);}/*** 系统任务调度器*/@Bean@ConditionalOnProperty(prefix = "system.scheduler", name = "enabled", havingValue = "true")@ConditionalOnMissingBeanpublic SystemTaskScheduler systemTaskScheduler() {log.info("初始化系统任务调度器");SystemTaskScheduler scheduler = new SystemTaskScheduler();scheduler.setPoolSize(systemProperties.getScheduler().getPoolSize());scheduler.setThreadNamePrefix(systemProperties.getScheduler().getThreadNamePrefix());return scheduler;}/*** 系统配置后处理器*/@PostConstructpublic void postConstruct() {log.info("系统自动配置完成,配置信息:{}", systemProperties);}
}/*** 系统属性配置*/
@Data
@ConfigurationProperties(prefix = "system")
public class SystemProperties {/*** 是否启用系统功能*/private boolean enabled = true;/*** 系统名称*/private String name = "RuoYi-Vue-Plus";/*** 系统版本*/private String version = "1.0.0";/*** 监控配置*/private MonitorConfig monitor = new MonitorConfig();/*** 缓存配置*/private CacheConfig cache = new CacheConfig();/*** 调度器配置*/private SchedulerConfig scheduler = new SchedulerConfig();@Datapublic static class MonitorConfig {private boolean enabled = true;private Duration interval = Duration.ofSeconds(30);private List<String> metrics = Arrays.asList("cpu", "memory", "disk");}@Datapublic static class CacheConfig {private String type = "local";private Duration ttl = Duration.ofMinutes(30);private int maxSize = 1000;private String keyPrefix = "system:";}@Datapublic static class SchedulerConfig {private boolean enabled = false;private int poolSize = 10;private String threadNamePrefix = "system-task-";}
}/*** 安全属性配置*/
@Data
@ConfigurationProperties(prefix = "security")
public class SecurityProperties {/*** 是否启用安全功能*/private boolean enabled = true;/*** 加密配置*/private EncryptionConfig encryption = new EncryptionConfig();/*** 访问控制配置*/private AccessControlConfig accessControl = new AccessControlConfig();@Datapublic static class EncryptionConfig {private String algorithm = "AES";private String key = "default-key";private String charset = "UTF-8";}@Datapublic static class AccessControlConfig {private boolean enableIpFilter = false;private List<String> allowedIps = new ArrayList<>();private List<String> blockedIps = new ArrayList<>();}
}

数据源配置类

/*** 数据源自动配置类*/
@Configuration
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {private static final Logger log = LoggerFactory.getLogger(DataSourceAutoConfiguration.class);/*** 主数据源配置*/@Bean@Primary@ConditionalOnProperty(prefix = "spring.datasource", name = "url")@ConfigurationProperties(prefix = "spring.datasource")public DataSource primaryDataSource() {log.info("初始化主数据源");return DataSourceBuilder.create().build();}/*** 从数据源配置*/@Bean@ConditionalOnProperty(prefix = "spring.datasource.slave", name = "url")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {log.info("初始化从数据源");return DataSourceBuilder.create().build();}/*** 动态数据源配置*/@Bean@ConditionalOnBean(name = {"primaryDataSource", "slaveDataSource"})@ConditionalOnProperty(prefix = "dynamic.datasource", name = "enabled", havingValue = "true")public DataSource dynamicDataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) {log.info("初始化动态数据源");Map<Object, Object> dataSourceMap = new HashMap<>();dataSourceMap.put("primary", primaryDataSource);dataSourceMap.put("slave", slaveDataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(dataSourceMap);dynamicDataSource.setDefaultTargetDataSource(primaryDataSource);return dynamicDataSource;}/*** JdbcTemplate配置*/@Bean@ConditionalOnMissingBean@ConditionalOnSingleCandidate(DataSource.class)public JdbcTemplate jdbcTemplate(DataSource dataSource) {log.info("初始化JdbcTemplate");return new JdbcTemplate(dataSource);}/*** 事务管理器配置*/@Bean@ConditionalOnMissingBean@ConditionalOnSingleCandidate(DataSource.class)public PlatformTransactionManager transactionManager(DataSource dataSource) {log.info("初始化事务管理器");return new DataSourceTransactionManager(dataSource);}
}/*** 动态数据源*/
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceType();}
}/*** 数据源上下文持有者*/
public class DataSourceContextHolder {private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();public static void setDataSourceType(String dataSourceType) {CONTEXT_HOLDER.set(dataSourceType);}public static String getDataSourceType() {return CONTEXT_HOLDER.get();}public static void clearDataSourceType() {CONTEXT_HOLDER.remove();}
}

@ConditionalOn条件注解

常用条件注解

/*** 条件注解示例配置类*/
@Configuration
public class ConditionalConfiguration {/*** 基于类路径的条件配置*/@Bean@ConditionalOnClass(RedisTemplate.class)public RedisService redisService() {return new RedisService();}/*** 基于缺失类的条件配置*/@Bean@ConditionalOnMissingClass("org.springframework.data.redis.core.RedisTemplate")public LocalCacheService localCacheService() {return new LocalCacheService();}/*** 基于Bean存在的条件配置*/@Bean@ConditionalOnBean(DataSource.class)public DatabaseService databaseService(DataSource dataSource) {return new DatabaseService(dataSource);}/*** 基于Bean缺失的条件配置*/@Bean@ConditionalOnMissingBean(CacheManager.class)public CacheManager defaultCacheManager() {return new ConcurrentMapCacheManager();}/*** 基于属性的条件配置*/@Bean@ConditionalOnProperty(prefix = "feature.email", name = "enabled", havingValue = "true",matchIfMissing = false)public EmailService emailService() {return new EmailService();}/*** 基于资源的条件配置*/@Bean@ConditionalOnResource(resources = "classpath:config/custom.properties")public CustomConfigService customConfigService() {return new CustomConfigService();}/*** 基于Web应用的条件配置*/@Bean@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)public WebMvcConfigurer webMvcConfigurer() {return new CustomWebMvcConfigurer();}/*** 基于非Web应用的条件配置*/@Bean@ConditionalOnNotWebApplicationpublic CommandLineRunner commandLineRunner() {return args -> System.out.println("非Web应用启动");}/*** 基于表达式的条件配置*/@Bean@ConditionalOnExpression("${feature.advanced.enabled:false} and ${feature.experimental.enabled:false}")public AdvancedFeatureService advancedFeatureService() {return new AdvancedFeatureService();}/*** 基于Java版本的条件配置*/@Bean@ConditionalOnJava(JavaVersion.EIGHT)public Java8SpecificService java8SpecificService() {return new Java8SpecificService();}
}

自定义条件注解

/*** 自定义操作系统条件注解*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnOperatingSystemCondition.class)
public @interface ConditionalOnOperatingSystem {/*** 操作系统类型*/OS value();enum OS {WINDOWS, LINUX, MAC, UNIX}
}/*** 操作系统条件实现*/
public class OnOperatingSystemCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnOperatingSystem.class.getName());if (attributes == null) {return false;}ConditionalOnOperatingSystem.OS requiredOS = (ConditionalOnOperatingSystem.OS) attributes.get("value");String osName = System.getProperty("os.name").toLowerCase();switch (requiredOS) {case WINDOWS:return osName.contains("windows");case LINUX:return osName.contains("linux");case MAC:return osName.contains("mac");case UNIX:return osName.contains("unix");default:return false;}}
}/*** 自定义环境条件注解*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnEnvironmentCondition.class)
public @interface ConditionalOnEnvironment {/*** 环境名称*/String[] value();/*** 匹配模式*/MatchMode mode() default MatchMode.ANY;enum MatchMode {ANY, ALL}
}/*** 环境条件实现*/
public class OnEnvironmentCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnEnvironment.class.getName());if (attributes == null) {return false;}String[] requiredEnvs = (String[]) attributes.get("value");ConditionalOnEnvironment.MatchMode mode = (ConditionalOnEnvironment.MatchMode) attributes.get("mode");String[] activeProfiles = context.getEnvironment().getActiveProfiles();Set<String> activeProfileSet = new HashSet<>(Arrays.asList(activeProfiles));if (mode == ConditionalOnEnvironment.MatchMode.ALL) {return activeProfileSet.containsAll(Arrays.asList(requiredEnvs));} else {return Arrays.stream(requiredEnvs).anyMatch(activeProfileSet::contains);}}
}/*** 使用自定义条件注解的配置类*/
@Configuration
public class CustomConditionalConfiguration {/*** Windows系统特定配置*/@Bean@ConditionalOnOperatingSystem(ConditionalOnOperatingSystem.OS.WINDOWS)public WindowsSpecificService windowsSpecificService() {return new WindowsSpecificService();}/*** Linux系统特定配置*/@Bean@ConditionalOnOperatingSystem(ConditionalOnOperatingSystem.OS.LINUX)public LinuxSpecificService linuxSpecificService() {return new LinuxSpecificService();}/*** 开发或测试环境配置*/@Bean@ConditionalOnEnvironment(value = {"dev", "test"}, mode = ConditionalOnEnvironment.MatchMode.ANY)public DebugService debugService() {return new DebugService();}/*** 生产环境配置*/@Bean@ConditionalOnEnvironment("prod")public ProductionService productionService() {return new ProductionService();}
}

自定义Starter开发

Starter项目结构

ruoyi-spring-boot-starter/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/ruoyi/starter/
│       │       ├── autoconfigure/
│       │       │   ├── RuoyiAutoConfiguration.java
│       │       │   ├── RuoyiProperties.java
│       │       │   └── condition/
│       │       ├── service/
│       │       │   ├── RuoyiService.java
│       │       │   └── impl/
│       │       └── util/
│       └── resources/
│           └── META-INF/
│               ├── spring.factories
│               └── spring-configuration-metadata.json
└── pom.xml

Starter核心实现

/*** RuoYi自动配置类*/
@Configuration
@EnableConfigurationProperties(RuoyiProperties.class)
@ConditionalOnProperty(prefix = "ruoyi", name = "enabled", havingValue = "true", matchIfMissing = true)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, RedisAutoConfiguration.class})
public class RuoyiAutoConfiguration {private static final Logger log = LoggerFactory.getLogger(RuoyiAutoConfiguration.class);@Autowiredprivate RuoyiProperties ruoyiProperties;/*** RuoYi核心服务*/@Bean@ConditionalOnMissingBeanpublic RuoyiService ruoyiService() {log.info("初始化RuoYi核心服务,配置:{}", ruoyiProperties);return new RuoyiServiceImpl(ruoyiProperties);}/*** RuoYi工具类*/@Bean@ConditionalOnMissingBeanpublic RuoyiUtils ruoyiUtils() {log.info("初始化RuoYi工具类");return new RuoyiUtils(ruoyiProperties);}/*** RuoYi缓存管理器*/@Bean@ConditionalOnClass(RedisTemplate.class)@ConditionalOnProperty(prefix = "ruoyi.cache", name = "enabled", havingValue = "true")public RuoyiCacheManager ruoyiCacheManager(RedisTemplate<String, Object> redisTemplate) {log.info("初始化RuoYi缓存管理器");return new RuoyiCacheManager(redisTemplate, ruoyiProperties.getCache());}/*** RuoYi事件监听器*/@Bean@ConditionalOnProperty(prefix = "ruoyi.event", name = "enabled", havingValue = "true")public RuoyiEventListener ruoyiEventListener() {log.info("初始化RuoYi事件监听器");return new RuoyiEventListener(ruoyiProperties.getEvent());}/*** RuoYi Web配置*/@Configuration@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)@ConditionalOnProperty(prefix = "ruoyi.web", name = "enabled", havingValue = "true")static class RuoyiWebConfiguration {@Beanpublic RuoyiWebMvcConfigurer ruoyiWebMvcConfigurer(RuoyiProperties ruoyiProperties) {log.info("初始化RuoYi Web配置");return new RuoyiWebMvcConfigurer(ruoyiProperties.getWeb());}@Beanpublic RuoyiInterceptor ruoyiInterceptor(RuoyiProperties ruoyiProperties) {log.info("初始化RuoYi拦截器");return new RuoyiInterceptor(ruoyiProperties.getWeb());}}/*** RuoYi数据库配置*/@Configuration@ConditionalOnClass(DataSource.class)@ConditionalOnProperty(prefix = "ruoyi.database", name = "enabled", havingValue = "true")static class RuoyiDatabaseConfiguration {@Beanpublic RuoyiDatabaseInitializer ruoyiDatabaseInitializer(DataSource dataSource, RuoyiProperties ruoyiProperties) {log.info("初始化RuoYi数据库初始化器");return new RuoyiDatabaseInitializer(dataSource, ruoyiProperties.getDatabase());}@Beanpublic RuoyiDataSourceHealthIndicator ruoyiDataSourceHealthIndicator(DataSource dataSource) {log.info("初始化RuoYi数据源健康检查");return new RuoyiDataSourceHealthIndicator(dataSource);}}
}/*** RuoYi属性配置*/
@Data
@ConfigurationProperties(prefix = "ruoyi")
public class RuoyiProperties {/*** 是否启用RuoYi功能*/private boolean enabled = true;/*** 应用名称*/private String appName = "RuoYi Application";/*** 应用版本*/private String version = "1.0.0";/*** 缓存配置*/private CacheProperties cache = new CacheProperties();/*** 事件配置*/private EventProperties event = new EventProperties();/*** Web配置*/private WebProperties web = new WebProperties();/*** 数据库配置*/private DatabaseProperties database = new DatabaseProperties();@Datapublic static class CacheProperties {private boolean enabled = true;private String prefix = "ruoyi:";private Duration ttl = Duration.ofMinutes(30);private int maxSize = 1000;}@Datapublic static class EventProperties {private boolean enabled = true;private boolean async = true;private int threadPoolSize = 10;}@Datapublic static class WebProperties {private boolean enabled = true;private String contextPath = "/";private List<String> allowedOrigins = Arrays.asList("*");private boolean enableCors = true;}@Datapublic static class DatabaseProperties {private boolean enabled = true;private boolean autoInit = false;private String initScript = "classpath:sql/init.sql";private boolean showSql = false;}
}

spring.factories配置

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.ruoyi.starter.autoconfigure.RuoyiAutoConfiguration# Application Listeners
org.springframework.context.ApplicationListener=\
com.ruoyi.starter.listener.RuoyiApplicationListener# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
com.ruoyi.starter.env.RuoyiEnvironmentPostProcessor# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.ruoyi.starter.diagnostics.RuoyiFailureAnalyzer

配置元数据

{"groups": [{"name": "ruoyi","type": "com.ruoyi.starter.autoconfigure.RuoyiProperties","sourceType": "com.ruoyi.starter.autoconfigure.RuoyiProperties"}],"properties": [{"name": "ruoyi.enabled","type": "java.lang.Boolean","description": "是否启用RuoYi功能","defaultValue": true},{"name": "ruoyi.app-name","type": "java.lang.String","description": "应用名称","defaultValue": "RuoYi Application"},{"name": "ruoyi.version","type": "java.lang.String","description": "应用版本","defaultValue": "1.0.0"},{"name": "ruoyi.cache.enabled","type": "java.lang.Boolean","description": "是否启用缓存功能","defaultValue": true},{"name": "ruoyi.cache.prefix","type": "java.lang.String","description": "缓存键前缀","defaultValue": "ruoyi:"},{"name": "ruoyi.cache.ttl","type": "java.time.Duration","description": "缓存过期时间","defaultValue": "30m"},{"name": "ruoyi.event.enabled","type": "java.lang.Boolean","description": "是否启用事件功能","defaultValue": true},{"name": "ruoyi.event.async","type": "java.lang.Boolean","description": "是否异步处理事件","defaultValue": true},{"name": "ruoyi.web.enabled","type": "java.lang.Boolean","description": "是否启用Web功能","defaultValue": true},{"name": "ruoyi.web.enable-cors","type": "java.lang.Boolean","description": "是否启用跨域支持","defaultValue": true}],"hints": [{"name": "ruoyi.cache.ttl","values": [{"value": "30m","description": "30分钟"},{"value": "1h","description": "1小时"},{"value": "1d","description": "1天"}]}]
}

配置属性绑定

属性绑定示例

/*** 应用配置属性*/
@Data
@Component
@ConfigurationProperties(prefix = "app")
@Validated
public class ApplicationProperties {/*** 应用基本信息*/@NotBlank(message = "应用名称不能为空")private String name;@NotBlank(message = "应用版本不能为空")private String version;@Email(message = "邮箱格式不正确")private String contactEmail;/*** 功能开关*/private FeatureFlags features = new FeatureFlags();/*** 第三方服务配置*/private Map<String, ThirdPartyService> services = new HashMap<>();/*** 环境相关配置*/private EnvironmentConfig environment = new EnvironmentConfig();@Datapublic static class FeatureFlags {private boolean enableCache = true;private boolean enableMonitoring = true;private boolean enableSecurity = true;private boolean enableAudit = false;}@Data@Validatedpublic static class ThirdPartyService {@NotBlankprivate String url;@Min(1000)@Max(30000)private int timeout = 5000;@Min(1)@Max(10)private int retryCount = 3;private Map<String, String> headers = new HashMap<>();}@Datapublic static class EnvironmentConfig {private String profile;private String region = "default";private boolean debug = false;private LogLevel logLevel = LogLevel.INFO;}public enum LogLevel {TRACE, DEBUG, INFO, WARN, ERROR}
}/*** 配置属性使用示例*/
@Service
public class ApplicationService {@Autowiredprivate ApplicationProperties applicationProperties;public void printApplicationInfo() {System.out.println("应用名称: " + applicationProperties.getName());System.out.println("应用版本: " + applicationProperties.getVersion());System.out.println("联系邮箱: " + applicationProperties.getContactEmail());FeatureFlags features = applicationProperties.getFeatures();System.out.println("缓存功能: " + (features.isEnableCache() ? "启用" : "禁用"));System.out.println("监控功能: " + (features.isEnableMonitoring() ? "启用" : "禁用"));Map<String, ThirdPartyService> services = applicationProperties.getServices();services.forEach((name, service) -> {System.out.println("服务 " + name + ": " + service.getUrl() + ", 超时: " + service.getTimeout() + "ms");});}
}

配置文件示例

# application.yml
app:name: "RuoYi管理系统"version: "2.0.0"contact-email: "admin@ruoyi.vip"features:enable-cache: trueenable-monitoring: trueenable-security: trueenable-audit: falseservices:payment:url: "https://api.payment.com"timeout: 10000retry-count: 3headers:Authorization: "Bearer token"Content-Type: "application/json"notification:url: "https://api.notification.com"timeout: 5000retry-count: 2environment:profile: "production"region: "cn-north-1"debug: falselog-level: INFO# 系统配置
system:enabled: truename: "RuoYi-Vue-Plus"version: "1.0.0"monitor:enabled: trueinterval: 30smetrics:- cpu- memory- diskcache:type: redisttl: 30mmax-size: 1000key-prefix: "system:"scheduler:enabled: truepool-size: 10thread-name-prefix: "system-task-"# 安全配置
security:enabled: trueencryption:algorithm: AESkey: "my-secret-key-123456"charset: UTF-8access-control:enable-ip-filter: trueallowed-ips:- "192.168.1.0/24"- "10.0.0.0/8"blocked-ips:- "192.168.1.100"

总结

本文详细介绍了Spring Boot自动配置的核心技术,包括:

  1. @Configuration配置类:系统配置类、数据源配置类的实现
  2. @ConditionalOn条件注解:常用条件注解、自定义条件注解的开发
  3. 自定义Starter开发:完整的Starter项目结构和实现
  4. 配置属性绑定:@ConfigurationProperties的使用和验证

这些技术是Spring Boot应用开发的基础,掌握这些内容有助于更好地理解和使用Spring Boot框架。

在下一篇文章中,我们将探讨Spring Security集成。

参考资料

  • Spring Boot自动配置原理
  • 条件注解详解
  • 自定义Starter开发指南

文章转载自:

http://TQuy8e6W.xqbbc.cn
http://HvHsKCDi.xqbbc.cn
http://BpUgB8NA.xqbbc.cn
http://orD3nXZR.xqbbc.cn
http://Wa6S15f5.xqbbc.cn
http://r6IzWjXo.xqbbc.cn
http://bFpkPtLI.xqbbc.cn
http://iRMaEVmw.xqbbc.cn
http://6HoINoc7.xqbbc.cn
http://kssIurtF.xqbbc.cn
http://VgVtxAr4.xqbbc.cn
http://fEjjgXZO.xqbbc.cn
http://JeIWtDEj.xqbbc.cn
http://9lbscQB8.xqbbc.cn
http://E64x9fNb.xqbbc.cn
http://vUUeFcQ3.xqbbc.cn
http://9BaGu9Ue.xqbbc.cn
http://6odABTNl.xqbbc.cn
http://u3sCdF7w.xqbbc.cn
http://OCpDWOnq.xqbbc.cn
http://Pktyl3t0.xqbbc.cn
http://0KlO5qxf.xqbbc.cn
http://nTzIEWiV.xqbbc.cn
http://6i3d391i.xqbbc.cn
http://igh2Stxe.xqbbc.cn
http://hirGTolo.xqbbc.cn
http://n2Gr5lXM.xqbbc.cn
http://5uBFXFJ4.xqbbc.cn
http://jrcbBk26.xqbbc.cn
http://Cq5D7kzi.xqbbc.cn
http://www.dtcms.com/a/369298.html

相关文章:

  • 一招快速识别你的电脑是机械硬盘还是固态硬盘
  • Centos7中部署Dify
  • 微服务架构下生鲜订单分布式事务解决方案指南
  • 电机试验平台:从实验到应用的创新突破
  • GitHub每日最火火火项目(9.5)
  • 十一、标准化和软件知识产权基础知识
  • B.50.10.07-分布式锁核心原理与电商应用
  • 语音识别系统的技术核心:从声音到文字的智能转换
  • WALLX全球大使圆桌论坛成功举办,13国代表共话未来,超千人共同参与
  • 本地化部署 DeepSeek
  • 开讲啦|MBSE公开课:第五集 MBSE中期设想(下)
  • Axure笔记
  • AMD三箭齐发:MI350已成AI加速器新王牌,256颗GPU的MI500“王炸”已预定2027
  • Docker Registry 实现原理、适用场景、常用操作及搭建详解
  • CAD:绘图功能
  • DeepSeek vs Anthropic:技术路线的正面冲突
  • spring cloud中使用openFeign时候get请求变post解决办法
  • 系统学习算法 专题十八 队列+宽搜
  • 【c++】c++第一课:命名空间
  • Graphpad 绘图(二):小鼠生存曲线绘制与数据记录分析详解
  • DNS基本功能搭建
  • C++Primerplus 编程练习 第十二章
  • 看见世界的另一种可能:Deepoc星眸(StarGaze)如何为视障生活带来曙光
  • Springboot实现国际化(MessageSource)
  • 告别Qt Slider!用纯C++打造更轻量的TpSlider组件
  • 数字孪生赋能:智能制造如何实现从“经验驱动”到“数据驱动”?
  • 穿越市场迷雾:如何在经济周期中保持理性与长期视角
  • Mac M4环境下基于VMware Fusion虚拟机安装Ubuntu24.04 LTS ARM版
  • Vue基础知识-脚手架开发-使用Axios发送异步请求+代理服务器解决前后端分离项目的跨域问题
  • 苍穹外卖 day03