尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Spring Boot启动流程与自动配置原理源码级拆解
有人问我Spring Boot 上手是不是特别简单引入几个 starter写几个注解项目就跑起来了。但真正碰到疑难杂症比如自动配置没有生效、Bean 被莫名覆盖、某个 Condition 明明满足条件却没加载不把启动过程和自动配置原理啃透就只能靠瞎猜。这篇文章我把 Spring Boot 的启动流程和自动配置机制从源码层面彻底拆开从SpringApplication的初始化、run()方法的执行、SpringBootApplication的组合注解到AutoConfigurationImportSelector的筛选链路、Conditional条件装配的底层判断一步步讲清楚并附上日常排查问题的调试手段。不管你是刚接触 Spring Boot 的初学者还是工作中经常被启动问题折磨的开发者读完都能建立一套完整的源码认知体系以后再遇到类似问题至少知道该去哪里看、该怀疑什么。1. 启动入口第一站SpringApplication 的初始化很多同学用 Spring Boot 是从SpringApplication.run(Application.class, args)这行代码开始的但这一行的背后SpringApplication的构造函数已经干了一系列关键事情。只有把这些前置动作搞明白后面run()方法执行时才不至于懵。1.1 构造函数里到底加载了哪些核心组件先看SpringApplication构造函数的源码逻辑它主要做了四件事public SpringApplication(ResourceLoader resourceLoader, Class?... primarySources) { this.resourceLoader resourceLoader; this.primarySources new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers new ArrayList( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass deduceMainApplicationClass(); }primarySources这里是传入的主配置类一般就是带着SpringBootApplication的那个类。webApplicationType通过 classpath 推断当前应用类型是 Servlet Web、Reactive Web 还是非 Web。ApplicationContextInitializer和ApplicationListener这两个东西是通过spring.factories加载的属于框架预留的扩展点。mainApplicationClass通过异常调用栈反推出包含main方法的类主要用来做一些日志输出和监控标识。这四步里最容易被忽略的是getSpringFactoriesInstances的加载机制。它本质上是读取 classpath 下所有META-INF/spring.factories文件按接口类型取出对应实现类然后实例化。Spring Boot 里有大量内置的ApplicationListener比如ClearCachesApplicationListener、ClasspathLoggingApplicationListener等都是在这个阶段被注册进来的。1.2 WebApplicationType 推断启动环境如何被感知WebApplicationType.deduceFromClasspath()这段代码非常典型它不依赖配置文件而是通过判断 classpath 下是否存在特定类来决定应用类型static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } // ... return WebApplicationType.SERVLET; }这段逻辑告诉了我们一个重要事实Spring Boot 很多“自动”的行为都是根据 classpath 里有没有某个类来判断的。这种思路贯穿始终后面的自动配置条件注解也大量采用同样的方式。比如你引入了spring-boot-starter-webclasspath 里就有了DispatcherServlet等相关类推断结果就是 Servlet Web 应用后续容器会和内嵌 Tomcat 绑定如果不引入 Web 相关依赖就是非 Web 应用webEnvironment相关的自动配置会全部跳过。1.3 主配置类的定位通过异常栈找“项目入口”deduceMainApplicationClass()的实现很有意思它不是扫描代码而是直接读取当前线程的调用栈private Class? deduceMainApplicationClass() { try { StackTraceElement[] stackTrace new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if (main.equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }这个方法在构造函数阶段执行因为SpringApplication.run()一定是从main方法调用进来的所以从调用栈里抓一个main方法所在的类非常可靠。找到的类会用作后续的日志输出、Actuator 健康检查信息的标识。这也是为什么你用SpringApplication.run(XxxApplication.class, args)传入的类和实际主类不一致时可能影响后续一些监控场景的展示。注意deduceMainApplicationClass()只做“推导”并不影响容器扫描路径。真正决定包扫描范围的是后面SpringBootApplication里的ComponentScan。2. run() 方法全景从设置环境到刷新容器SpringApplication.run()是整个启动过程的执行主体包含监听器触发、环境准备、容器创建、容器刷新等环节。我把其中最重要的几个阶段拆开讲。2.1 启动监听器机制SpringApplicationRunListener 的 SPI 加载进入run()方法后第一件大事是获取SpringApplicationRunListenersSpringApplicationRunListeners listeners getRunListeners(args); listeners.starting();SpringApplicationRunListener是 Spring Boot 定义的一套“启动生命周期监听器”它和ApplicationListener不一样前者监听的是 Spring Boot 启动过程中各个阶段后者监听的是容器内部事件。常见的EventPublishingRunListener会把启动阶段的事件转译为ApplicationEvent广播给所有ApplicationListener。SpringApplicationRunListener接口定义了这些阶段starting()启动刚开始环境还没准备。environmentPrepared()环境已准备好。contextPrepared()容器已创建并设置好环境但还未刷新。contextLoaded()主配置类和普通配置类已加载进容器。started()容器刷新完成ApplicationRunner执行前。ready()启动完成后。failed()启动失败时。理解这套阶段模型对排查启动日志非常有用。当你看到某些 Bean 在contextLoaded()之后才被初始化说明广播阶段已经进入容器刷新环节如果你要实现类似“启动完打日志”的功能最好注册ApplicationRunner而不是直接在监听器里乱写。2.2 Environment 准备与配置属性来源prepareEnvironment()这段逻辑负责构建ConfigurableEnvironment。它会先判断应用类型然后创建对应的Environment实现ConfigurableEnvironment environment getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment);Environment在 Spring Boot 里是个非常核心的概念它管理的不是数据库连接等业务属性而是“配置来源”包括系统属性System.getProperties()环境变量System.getenv()application.properties/application.ymlapplication-{profile}.properties等 profile 配置文件Servlet 参数如果 Web 环境配置中心扩展的数据源这里有个容易踩坑的点很多人以为application.yml里的配置优先级最高其实不是。Spring Boot 的配置优先级有完整顺序比如系统属性和环境变量就高于配置文件命令行参数又会高于系统属性。所以线上出现“改了配置文件没生效”的情况优先怀疑是不是环境变量或启动参数里覆盖了同一个 key。2.3 prepareContext 阶段做了哪些铺垫环境准备好之后run()会创建ApplicationContext。不同 Web 类型对应不同容器Servlet WebAnnotationConfigServletWebServerApplicationContextReactive WebAnnotationConfigReactiveWebServerApplicationContext非 WebAnnotationConfigApplicationContext创建完容器后进入prepareContext()重点动作有两个一是给容器设置 Environment、添加ApplicationListener二是注册BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor等组件。然后通过load()方法把主配置类解析成BeanDefinition注册进容器。protected void load(ApplicationContext context, Object[] sources) { // ... if (context instanceof BeanDefinitionRegistry registry) { // 将主配置类包装成 AnnotatedBeanDefinitionReader 后注册 AnnotatedBeanDefinitionReader reader new AnnotatedBeanDefinitionReader(registry); reader.register(source); } }这一步完成后容器里已经持有主配置类的BeanDefinition但 Bean 还没有实例化真正让容器跑起来的是接下来的refreshContext()。2.4 refreshContext整个 IoC 容器加载的关键动作refreshContext()最终调用的是 Spring 原生AbstractApplicationContext.refresh()里面的流程是 Spring 框架的核心也是整个 Spring Boot 启动过程里信息量最大的部分public void refresh() throws BeansException, IllegalStateException { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); }其中invokeBeanFactoryPostProcessors()是我们理解自动配置的最关键一环。自动配置类在这里被解析、注册、排序、条件判断全部都在ConfigurationClassPostProcessor的触发下完成。这一步跑完之后容器内的BeanDefinition基本齐了后续进入finishBeanFactoryInitialization()才开始真正实例化单例 Bean。3. 自动配置的入口SpringBootApplication 的三重组合很多人知道SpringBootApplication是个组合注解但组合注解里的每个元注解到底解决了什么问题不一定清楚。这一节层层拆开。3.1 SpringBootConfiguration 与 ComponentScan 的作用半径SpringBootConfiguration其实就是Configuration加了元注解标记表示这是一个配置类。唯一区别是 Spring Boot 内部会通过SpringBootConfiguration判断哪些类是“根配置类”避免被其他机制重复处理。SpringBootApplication里还包含了ComponentScan扫描的是主配置类所在包及其子包。所以工程里 controller、service、repository 都要放在主类所属包下这个规则经常有人违背导致 Bean 找不到启动却不报错只有调用时报空指针。另外注意ComponentScan里有过滤器ComponentScan(excludeFilters { Filter(type FilterType.CUSTOM, classes TypeExcludeFilter.class), Filter(type FilterType.CUSTOM, classes AutoConfigurationExcludeFilter.class) })TypeExcludeFilter是给用户扩展用的用来排除特定 BeanAutoConfigurationExcludeFilter则是防止自动配置类被普通组件扫描再次拾取避免配置类被重复加载。3.2 EnableAutoConfiguration为什么要二次封装 ImportEnableAutoConfiguration本身是个带Import的注解AutoConfigurationPackage Import(AutoConfigurationImportSelector.class) public interface EnableAutoConfiguration { }这里有两个关键点。AutoConfigurationPackage会注册一个AutoConfigurationPackages.Registrar它把主配置类所在包记录下来后续某些自动配置类需要扫描实体类时会读取这个包名。比如JpaRepositoriesAutoConfiguration要扫描Entity它不知道你的包是啥就会通过AutoConfigurationPackages拿到包的基准位置。Import(AutoConfigurationImportSelector.class)则是整个自动配置加载的核心。为什么要用Import而不是直接列举配置类因为自动配置类太多而且需要根据条件动态筛选只能交给一个“选择器”在运行时去读取候选配置然后筛选出真正需要注册的配置类。3.3 从 spring.factories 到 AutoConfiguration.imports 的变化与原因Spring Boot 2.7 之前自动配置类的候选列表写在META-INF/spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration\ com.example.autoconfigure.MyAutoConfiguration,\ ...Spring Boot 2.7 之后新增了META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件并把内置自动配置迁移到这个文件里。Spring Boot 3.x 则完全移除了自动配置在spring.factories中的支持。为什么这样改原因主要有两个spring.factories里承载的东西太杂包括ApplicationListener、ApplicationContextInitializer、EnvironmentPostProcessor、自动配置类等一次性加载解析会带来不必要的开销。AutoConfiguration.imports支持按行读取和增量编译工具配合更好还能保证配置顺序可预测。自己写 starter 时注意版本差异。如果只兼容 Spring Boot 2.7直接使用AutoConfiguration.imports即可如果要兼容老版本可能需要同时提供spring.factories版本。4. AutoConfigurationImportSelector自动配置的编排者这一节进入源码深水区。AutoConfigurationImportSelector是整个自动配置机制的“导演”它处理“加载哪些自动配置类”“以什么顺序加载”“哪些被排除掉”这几件事。4.1 DeferredImportSelector 在刷新流程中的执行位置AutoConfigurationImportSelector实现的是DeferredImportSelector而不是普通ImportSelector。它的特殊之处在于Spring 会在解析完所有普通配置类之后再回头处理DeferredImportSelector的selectImports()。为什么要延迟因为自动配置类大量依赖ConditionalOnMissingBean来判断容器里是否已经有用户自定义的 Bean如果自动配置类先于用户配置类解析就无法准确判断哪些 Bean 是用户手动注册的。延迟处理保证了用户配置优先注册自动配置再根据容器现状做条件决策。DeferredImportSelector还有一个getImportGroup()方法自动配置会返回AutoConfigurationGroup把所有自动配置类收集到一个分组里统一排序和去重。4.2 getAutoConfigurationEntry 的完整筛选链路AutoConfigurationImportSelector.AutoConfigurationGroup.process()内部调用getAutoConfigurationEntry()完整流程如下protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes getAttributes(annotationMetadata); // 1. 从 AutoConfiguration.imports 加载所有候选配置类 ListString configurations getCandidateConfigurations(annotationMetadata, attributes); // 2. 去重 configurations removeDuplicates(configurations); // 3. 获取 exclusions 排除集合支持 SpringBootApplication(exclude...) 和配置文件排除 SetString exclusions getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); // 4. 读取自动配置类的排序关联 configurations getConfigurationClassFilter().filter(configurations); // 5. 触发自动配置导入事件 fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }这个流程里的五个步骤每一步都可能产生问题。比如你配置了spring.autoconfigure.exclude或者excludeName这些排除项会在第 3 步被移除如果你排除的是不存在的配置类checkExcludedClasses会直接抛出异常要求你先确认类全限定名是否正确。第 4 步的过滤器会结合spring-autoconfigure-metadata.properties元数据做一次预筛选不满足基本条件的类直接跳过避免后续无谓的类加载。4.3 自动配置类排序AutoConfigureBefore/After 与元数据Spring Boot 的自动配置类之间往往存在依赖关系。例如RedisAutoConfiguration需要先于RedisReactiveAutoConfiguration注册RedisConnectionFactory的 Bean因此需要排序保证。排序主要有两种方式在自动配置类上使用AutoConfigureBefore、AutoConfigureAfter、AutoConfigureOrder注解。在AutoConfiguration.imports文件顶部通过#注释声明顺序如# Auto Configure org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate ...按 Spring Boot 的设计文件的声明顺序和注解共同决定最终排序。AutoConfigurationSorter会对这些依赖关系做拓扑排序排序失败时会有明确的循环依赖报错。提示自己写 starter 时如果自动配置类依赖另一个自动配置类不要通过ConditionalOnClass硬等最好明确用AutoConfigureBefore/AutoConfigureAfter声明否则在依赖关系复杂时可能会出现完全不可预期的加载顺序。5. 条件装配Conditional 系列注解的执行机理自动配置类之所以能“按需生效”核心秘密在于条件注解。没有条件注解自动配置类一旦加载就会全量注册这会引入大量不必要的 Bean项目直接臃肿到爆炸。5.1 为什么用 ClassLoader 判断类是否存在最常见的条件是ConditionalOnClass。它的作用是判断 classpath 下是否存在指定的类。源码里的OnClassCondition主要通过ClassUtils.isPresent()来做判断protected boolean isPresent(String className, ClassLoader classLoader) { if (classLoader null) { classLoader ClassUtils.getDefaultClassLoader(); } try { for (String classNameToCheck : ClassUtils.getAllInterfacesForClass(className, classLoader)) { // ... } Class.forName(className, false, classLoader); return true; } catch (Throwable ex) { return false; } }注意这里用的是Class.forName(className, false, classLoader)第二个参数false表示加载类但不初始化静态代码块。为什么不用try { Class.forName(className) }或者import因为import在编译期就决定了无法做运行时判断而普通Class.forName(className)会触发静态代码块执行可能导致不必要的副作用。这里用false就是只探测类的存在性不执行任何静态逻辑。日常排查中如果ConditionalOnClass失效首先看依赖是否真的被引入了其次看类名有没有拼错最后看是不是这个类在某个 jar 里被provided或optional排除了。5.2 常用条件注解的运行逻辑和失效场景除ConditionalOnClass外还有几个高频条件注解注解作用典型失效原因ConditionalOnBean容器中存在指定 Bean 时生效Bean 定义顺序晚于自动配置判断或 Bean 是懒加载ConditionalOnMissingBean容器中不存在指定 Bean 时生效用户自定义 Bean 类型不匹配或注册了多个同类型候选ConditionalOnProperty配置项满足条件时生效配置项 key 拼写错误matchIfMissing理解错误ConditionalOnExpressionSpEL 表达式为 true 时生效表达式引用的配置项不存在或写法错误ConditionalOnSingleCandidate容器中指定 Bean 只有一个候选时生效注册了多个实现类且未加Primary这里最坑的往往是ConditionalOnBean。因为 Spring 的Conditional是在BeanDefinition注册阶段就执行的此时很多 Bean 还没创建所以ConditionalOnBean只能看到已经注册的BeanDefinition。如果你自定义的 Bean 是通过Bean方法注册并且在同一个配置类里其注册顺序可能晚于自动配置类判断的时机导致ConditionalOnBean不生效。Spring Boot 官方其实不推荐在自动配置里用ConditionalOnBean而是建议用ConditionalOnMissingBean来兜底。因为前者的判断时机容易出问题。5.3 动手写一个自定义 Condition 并应用到 starter理解了条件注解的原理自己写一个 Condition 就不难了。假设我想写一个只有在配置文件里打开myapp.enabledtrue时才生效的自动配置public class MyFeatureCondition implements Condition { Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment context.getEnvironment(); return environment.getProperty(myapp.enabled, Boolean.class, Boolean.FALSE); } }在自动配置类上使用Configuration Conditional(MyFeatureCondition.class) public class MyFeatureAutoConfiguration { Bean public MyFeatureService myFeatureService() { return new MyFeatureService(); } }把这类文件放进 starter 的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中就完成了自动配置的闭环。当然生产环境一般直接用现成的组合注解就行但理解Condition的实现机制能帮你准确判断 Spring Boot 内置条件为什么失败。6. 排查自动配置问题的 4 个实战手段源码看再多最后还是要落到“怎么排查问题”上。这一节分享几个我实际工作中经常用的方法。6.1 --debug 参数与 ConditionEvaluationReport启动时带上--debugSpring Boot 会在日志中输出自动配置报告。关键是能看到两类信息Positive matches匹配成功的自动配置类。Negative matches不匹配的自动配置类以及不匹配原因。例如Negative matches中会显示RedisAutoConfiguration: Did not match: - ConditionalOnClass did not find required class org.springframework.data.redis.core.RedisOperations这一行信息可以直接告诉你失败原因省去大量猜测时间。ConditionEvaluationReport是这个报告的数据来源它记录每一个自动配置类的条件匹配结论。也可以在 Actuator 的conditions端点中查看 JSON 格式的报告。6.2 日志级别调优哪些 Logger 值得打开 DEBUG--debug会打开非常多的日志生产环境不适合长期开启。更精细的做法是只打开特定包的 DEBUG 日志logging.level.org.springframework.boot.autoconfigureDEBUG logging.level.org.springframework.boot.web.embedded.tomcatDEBUG logging.level.org.springframework.context.annotationDEBUGorg.springframework.context.annotation包下的ConfigurationClassPostProcessor、ConfigurationClassParser会输出配置类的解析过程能看到自动配置类被加载、排除的详细日志排查 Bean 加载顺序问题时尤其有用。6.3 断点调试的黄金位置从 ConfigurationClassParser 入手如果你想看某个自动配置类到底是什么时候被处理的、条件是否满足可以在ConfigurationClassParser#processImports方法打个断点。它会遍历所有Import的类包括DeferredImportSelector。另一个黄金断点在ConditionEvaluator#shouldSkip。每次条件注解执行判断时都会经过这里通过断点观察Condition实例和metadata的属性能直接确认条件判断的输入和输出。6.4 元数据文件对加载性能的优化spring-autoconfigure-metadata.propertiesSpring Boot 内置 jar 里有META-INF/spring-autoconfigure-metadata.properties文件它的作用是在加载自动配置类之前先根据简化条件做粗筛。举例org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.AutoConfigureAfterorg.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.ConditionalOnClassorg.springframework.data.redis.core.RedisOperations条件过滤是针对配置类的“快速失败”机制可以避免加载大量不需要的配置类对启动性能有很大帮助。自己写 starter 时也可以通过 Spring Boot 提供的注解处理器自动生成元数据文件dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-configuration-processor/artifactId optionaltrue/optional /dependency配合ConfigurationProperties注解能在编译期生成spring-configuration-metadata.json虽然没有AutoConfigureAfter和ConditionalOnClass等元数据但 IDE 提示会友好很多。对于自动配置元数据还可以通过AutoConfiguration(after XxxAutoConfiguration.class)声明顺序Spring Boot 会根据它生成对应的AutoConfigureAfter元数据。在实际使用中我的建议是先看条件评估报告再看配置类解析日志最后才上断点调试。不要一上来就深挖源码那样反而浪费时间。理解 Spring Boot 启动过程和自动配置原理核心在于把握两个关键点一是ConfigurationClassPostProcessor如何解析配置类并触发AutoConfigurationImportSelector二是ConditionEvaluator如何利用条件注解做动态过滤。这两条线串联起来整个自动配置机制就一张图装下了。最后再分享一个小技巧如果你实在不确定某个自动配置类为什么被跳过把--debug输出里的Negative matches复制到文本编辑器里全局搜索你的目标配置类名失败原因就在匹配注释下面这一行字往往能直接指引你找到问题的答案。
RELATED

相关推荐

WolfCut开源视频编辑器:Rust+Tauri打造本地化专业剪辑工具

WolfCut开源视频编辑器:Rust+Tauri打造本地化专业剪辑工具

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/13 20:35:10
Spring AI框架:企业级Java应用集成AI的最佳实践

Spring AI框架:企业级Java应用集成AI的最佳实践

1. Spring AI框架概述与核心价值 Spring AI作为Java生态中首个标准化AI集成框架,正在彻底改变企业级智能应用的开发方式。这个由Spring官方团队孵化的项目,本质上是一个AI中间件层,它通过统一的编程模型屏蔽了底层AI服务的复杂性。我在实际企…

📅 2026/9/13 20:35:10
Django学生选课系统:ORM设计、事务与Admin后台实践

Django学生选课系统:ORM设计、事务与Admin后台实践

简介:一个使用 Django 框架开发的学生选课管理系统源码包,面向 Python 初学者的 Web 实战项目,可帮助掌握 MVC 架构在真实项目中的落地方式。系统包括学生登录认证、课程浏览、选课与退选等基本功能,完整涉及模型定义、视图函数、…

📅 2026/9/13 20:35:10
MORE NEWS

更多资讯

📰

LeetCode-Go 动态规划实战:用 Go 实现带障碍物的路径计数(Unique Paths II,第 63 题)

LeetCode-Go 动态规划实战:用 Go 实现带障碍物的路径计数(Unique Paths II,第 63 题) 【免费下载链接】LeetCode-Go ✅ Solutions to LeetCode by Go, 100% test coverage, runtime beats 100% | LeetCode 题解 项目地址: https…

📰

OpenAI Agents SDK 怎么改默认模型并调整 GPT-5 推理参数

OpenAI Agents SDK 怎么改默认模型并调整 GPT-5 推理参数 【免费下载链接】openai-agents-python A lightweight, powerful framework for multi-agent workflows 项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python 在 openai-agents-python&…

📰

Ruby 语法级计算器:TRICK 2025 获奖作品「纯 Ruby 语法加法」原理与玩法

Ruby 语法级计算器:TRICK 2025 获奖作品「纯 Ruby 语法加法」原理与玩法 【免费下载链接】ruby The Ruby Programming Language 项目地址: https://gitcode.com/GitHub_Trending/ru/ruby 本文基于 Ruby 仓库中 TRICK 2025(第 5 届 Transcendental…

📰

CAMEL Loaders 模块完全指南:从文档解析、网页抓取到 RAG 数据接入

CAMEL Loaders 模块完全指南:从文档解析、网页抓取到 RAG 数据接入 【免费下载链接】camel 🐫 CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org 项目地址: https://gitcode.com/G…

📰

3条命令跑通 kohya_ss Docker 部署:从克隆到训练界面

3条命令跑通 kohya_ss Docker 部署:从克隆到训练界面 【免费下载链接】kohya_ss 项目地址: https://gitcode.com/GitHub_Trending/ko/kohya_ss 第三次在 pip install torch 的 CUDA 版本报错里打转时,可以停下了:kohya_ss 是 Stable …

📰

Lithe-IDEA:Rust+JavaFX打造的轻量开源Java IDE

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬