Spring全家桶这几个字,劝退的威力比什么都大。我见过太多人从Java入门到放弃,就卡在“全家桶”这个入口上:Spring Framework还没弄明白,又看到Spring Boot、Spring MVC、Spring Security、Spring Cloud,后面还跟着Spring Data、Spring Batch、Spring StateMachine,目录翻下来第一反应就是——这得学到哪年?这篇文章想分享的不是又一个收藏吃灰的路线图,而是把我看过的、带过的、自己踩过的Spring全家桶学习经验完整捋一遍,告诉你先学什么、怎么学、哪些内容必须动手做到什么程度,哪些东西可以往后放。内容适合正在学Java的在校生、自学转行的朋友,也适合那些已经把Spring Boot用起来但总觉得心里没底的新人。
1. 先别急着学框架,把全家桶当一盘菜拆开看
1.1 Spring本来只有一个核心,桶是慢慢变大的
很多人对“Spring全家桶”的第一反应是恐惧,因为名字太多。但实际上,Spring家族真正的根只有一个:Spring Framework。IOC容器、AOP、Bean生命周期、事务抽象,这些东西全部长在Spring Framework这棵老树上。后来衍生出的Spring Boot,本质上是“用自动配置把繁琐的样板代码吃掉”,Spring MVC是Web层框架,Spring Security管认证授权,Spring Cloud则是把分布式的复杂度封装成一套套顺手工具。理解了这条主线,“全家桶”就不是几十个孤立技术,而是围绕“对象管理和业务能力”长出来的一圈枝叶。
我见过一个错误的学法,是从Spring Boot的starter开始学,上来就写接口、连数据库,项目跑得飞起,但一问什么是Bean,为什么两个Service互相注入会报循环依赖,整个人就愣住了。这就是典型的“会用脚手架,不懂内核”。全家桶的容错率看似很高,出问题的时候却必须回到Spring Framework底层去找答案。所以第一课不是学哪个新组件,而是先弄清楚Spring凭什么能管理那么多对象。
1.2 用一张表看清全家桶成员到底谁管什么事
给全家桶分门别类之前,先泼一盆冷水:你不需要一开始就把所有成员都学会。很多组件是“要用的时候再学”,学习顺序和重要程度完全不同。我按实战中出现频率,把常见成员的功能定位、使用场景和推荐学习时机列在下面。
| 成员 | 职责定位 | 典型使用场景 | 建议学习时机 |
|---|---|---|---|
| Spring Framework | 容器内核,管理Bean生命周期与依赖 | 所有Spring项目的地基 | 第一个学,且要学透 |
| Spring MVC | Web层框架,处理HTTP请求与路由 | 后端接口开发,登录注册、订单模块 | 第二阶段学,配合实战 |
| Spring Boot | 自动化装配,降低工程配置成本 | 快速搭项目、微服务底座 | 紧跟Framework之后 |
| Spring Security | 认证、授权、会话与OAuth2 | 登录注册、权限控制,与量大系统集成 | 有Web项目基础后再学 |
| Spring Cloud | 分布式架构全家桶,含注册中心、网关、配置中心 | 微服务拆分、服务间调用、配置管理 | 有分布式需求或面试前学 |
| Spring Data | 统一数据访问抽象层 | JPA、Redis、Elasticsearch等数据源操作 | 用到具体数据源时再学 |
| Spring Batch | 批量处理框架 | 定时报表、大批量数据清洗 | 有明显批处理需求再学 |
| Spring StateMachine | 状态机框架,管理状态流转 | 订单状态、审批流程、工单流转 | 进阶阶段,有业务场景再深入 |
这张表的意思是,学习顺序应该是“先内核、后Boot、再Web、按需补生态”。Spring Batch和Spring StateMachine这类组件,多数业务开发几年都不一定碰一次,硬啃纯属浪费精力。真正决定你能不能干活的是前三排,决定你架构能力的是Spring Cloud那排,剩下的是锦上添花。
2. 正确学习姿势:四阶段递进,别一上来就摸微服务
2.1 阶段一:手写一个微缩Spring,把IOC和AOP吃进骨头里
我强烈建议每个想学好Spring的人都去试试“手写Spring”,不是让你重新造轮子,而是用几百行代码把IOC容器和AOP的真实工作过程模拟一遍。这件事看起来抽象,但它能一次性解释清楚三个面试常客:Bean是怎么被创建出来的、属性是怎么被注入的、代理对象是怎么套上去的。
具体做法分三步。第一步,写一个简化版容器,用注解扫描包路径,把带有@Component注解的类找出来,反射创建实例放到Map里,再遍历字段完成依赖注入,这就是最基础的IOC雏形。第二步,加入BeanPostProcessor概念,在Bean初始化前后插入扩展点,模拟Spring的bean后置处理器机制。第三步,用动态代理生成代理对象,在方法调用前后插入拦截逻辑,这就是AOP的原型。我当年做完这套小项目后再去看Spring源码,很多以前看不懂的类名忽然都有了画面感,因为那些类正是在做我自己写过的逻辑。
这个阶段不需要追求代码完善,也不需要覆盖所有注解,核心是建立“容器思维”。你会真正理解为什么Spring要管对象之间的依赖关系,而不是让人自己new——因为解耦。你也会理解为什么Spring能到处“侵入”方法做日志、做事务,因为这些能力建立在动态代理之上。把这些想明白,后面看任何Spring技术文档都会顺畅很多。
2.2 阶段二:Spring Boot先把自动配置玩明白,而不是停留在会用
有了内核基础,再上Spring Boot就基本没有认知压力。这个阶段的目标不是“能跑一个Hello World”,而是搞清楚Spring Boot到底替你做了什么。核心就五个字:自动配置。你引入一个spring-boot-starter-web,为什么Tomcat就起来了?为什么写一个@RestController就能接收请求?答案都在spring-boot-autoconfigure里。
我建议用一次实操来验证理解:新建工程,不看任何教程,自己尝试回答两个问题。第一个问题,修改端口号有几种方式?最简单的改application.properties里server.port=8081,也可以启动时传参--server.port=8082,还能用环境变量覆盖。第二个问题,如果要让一个自定义配置类只在特定条件下生效,应该怎么做?答案是@ConditionalOnProperty或@ConditionalOnClass。这两个问题答完,你对自动配置的“触发条件”就会有自己的理解。
除了自动配置,Spring Boot还有一个高频操作和MyBatis集成。把mybatis-spring-boot-starter加进来,配好数据源,写一个@Mapper接口,一个Service,一个Controller,整个链路就跑通了。这里我要多啰嗦一句:集成MyBatis时最容易出问题的不是SQL,而是数据源配置写错。地址、账号、密码、驱动类,任何一个不当都对不上,报错还往往很绕。建议从HikariCP默认连接池开始,不要一上来就换Druid,减少变量。
2.3 阶段三:用Spring Boot + Spring MVC + Vue,做一个真实的登录注册模块
很多教程让你学完Spring Boot就去做电商、做商城、做后台管理系统,方向对,但范围太大容易烂尾。我更推荐只做一个“登录注册与用户管理模块”,它麻雀虽小、五脏俱全:有Web层处理请求、有数据层读写用户表、有安全层处理密码校验和登录态、有前后端联调,这是完整闭环的最小项目。
我自己带人时,通常要求在这个模块里实现四个功能:用户注册、用户登录、查看个人资料、修改密码。注册要处理用户名重复校验和密码加密,登录要校验账号密码并生成会话凭证,改密码要验证原密码正确性,资料查询要坚持“只能查自己”。这四个功能里,密码绝不能用明文存储,我用BCrypt加密;会话凭证可以用Session,也可以发一个Token存到前端,取决于你后续是否打算做前后端分离。Spring Security在这个阶段可以先不引入,手动用拦截器做一个简单的登录状态校验,反而更能让你理解安全认证的痛点在哪里。等你手动实现一遍“登录后放行、未登录拦截”,再学Spring Security,你才会感激它封装的每个Filter都有意义。
前端部分用Vue就行,不需要很复杂。用Vue CLI或Vite起一个项目,封装axios实例,在请求拦截器里带上Token,在路由守卫里判断登录状态。这里最容易踩的坑是跨域:后端没开CORS或配置不对,前端请求永远失败。建议后端先写一个全局CORS配置,Allow Origin和Allow Headers都要列全,否则排查起来非常浪费时间。做完这个模块,你已经算是一个“能独立做Web功能”的开发者,可以自信地说自己会用Spring全家桶了。
2.4 阶段四:Spring Cloud与Security、状态机等生态力
到了第三阶段之后,你才有资格碰Spring Cloud和Spring Security这些偏架构的组件。Spring Cloud的核心不是“学会每个组件”,而是建立分布式思维:服务多了怎么互相发现、怎么统一入口、怎么集中配置、怎么处理调用失败。我建议不要先啃理论PDF,而是把一个三服务的小项目跑起来:一个注册中心,两个业务服务,一个网关,让两个业务服务之间用OpenFeign互相调用,再把配置放到配置中心。这套跑通,你对服务治理的理解立刻超过只看教程的人。
Spring Security值得单独投入两周。它最劝退的地方是Filter链特别长,默认配置又把登录页、会话策略都包好了,导致新手对着日志一头雾水。我的学习方法是先关闭所有自定义配置,用默认账号密码跑一遍登录流程,再看它生成了哪些Session和Cookie,最后才写自定义UserDetailsService。你要记住一个关键结论:Spring Security的本质是过滤器链,每个请求依次经过认证、授权、异常处理等Filter,弄清楚这条链,比背一百个API管用。
生存状态机应用也是一个很有意思的进阶方向,它的价值在于幂等和可追溯。比如订单状态“待支付→已支付→已发货→已完成”,用if-else写会越来越乱,用Spring StateMachine把状态和事件建模,代码清晰度会高很多。这个组件不是必须学,但如果你碰到状态流转复杂的业务,它值得你在实战中尝试。
3. 核心知识点这样理解,才算真学会
3.1 三级缓存:我劝你别背,背是背不走的
“Spring三级缓存原理”是面试高频词,但很多人的理解停留在“三个Map存不同阶段的对象”,一追问就露馅。我先说结论:三级缓存解决的是singleton作用域下Bean的循环依赖问题,也就是A依赖B、B依赖A时,怎么在不报错的情况下完成双方实例化。
一级缓存singletonObjects存放“完整初始化好的Bean”,二级缓存earlySingletonObjects存放“提前暴露的半成品Bean”,三级缓存singletonFactories存放的是“能生成半成品Bean的工厂”。常规流程是先创建A,发现A依赖B,去创建B,B又依赖A,这时候三级缓存就把A的早期引用给了B,B完成创建,A再继续完成自己的后续步骤。为什么要三级而不是二级?因为Spring不仅要暴露半成品,还希望在暴露之前有机会执行AOP代理的创建。三级缓存存工厂对象,可以做到“允许代理提前生成”;如果你直接存半成品对象,代理的时机就卡死了。这就是三级缓存存在的真正理由,它不是面试官刁难你,而是Spring团队为处理复杂对象依赖关系留下的精巧设计。
我给新人的学习方法是:把这段逻辑画成一张时序图,用A和B两个类实际跑一遍循环依赖场景,在三个Map的添加和移除点打断点,亲眼看看对象是怎么流转的。五分钟断点比两小时网课都管用。需要特别提醒的是,循环依赖虽然有三级缓存兜底,但生产环境里不该故意制造循环依赖,它会让Bean的创建顺序变得非常隐晦,能拆开就拆开。
3.2 AOP不只能做日志,你把切面用窄了
AOP是Spring里最有“魔法感”的部分,可惜大多数人只用它打日志。我会用@Aspect切面、@Around环绕通知,在方法前后记录参数和执行时间,这当然是经典用法,但它更厉害的是提供了“无侵入扩展”的工程思路。
举个业务例子:你要在所有需要管理权限的接口上校验当前用户是否有操作权限,最原始的做法是每个方法里写校验代码,十次、二十次地重复。用AOP的话,写一个@RequirePermission注解,定义一个切面,在切面里读取注解的参数并校验权限,业务代码干干净净只做业务,这就是“横切关注点”的真正价值。日志、事务、权限校验、接口耗时统计、限流防刷,这些都是切面的主场。
AOP的实现机制也很值得说透:Spring AOP默认在运行时用代理实现,接口存在时用JDK动态代理,没有接口时用CGLIB生成子类代理。这意味着被切的方法不能是final的、不能被private修饰,否则代理没机会插手。很多人配置了切面却一直不生效,先别怀疑人生,检查依赖里有没有spring-boot-starter-aop,检查类上有没有@Aspect和@Component,检查方法权限修饰符,这三个地方占掉八成问题。
3.3 数据访问与事务:MyBatis只是搭桥,事务才是命门
Spring Boot + MyBatis的组合,网上能下载到一大堆开源商城源码,多商户跨境商城、仿天猫、秒杀系统,看着都挺诱人。但我劝你别抱着“下载下来直接跑”的心态去用这些源码,十份源码里能有两份空依赖、三份缺数据库脚本、三份留有测试脏数据、还有隐藏硬编码的账号密码,直接跑起来反而会把你拖进更深的坑。
用MyBatis时有三件事必须自己动手做一遍:第一,手写一个简单的动态SQL,比如条件查询用户列表时用 标签拼接条件;第二,配置驼峰映射,让数据库的user_name字段自动映射到userName属性;第三,批量插入一批数据,感受一下ExecutorType的变化。做完这三件事,MyBatis在你眼里就不再是一个“自动映射的黑盒”。
真正决定数据一致性的,是Spring事务。我用一个清零场景来理解:转账接口里先扣款、再入账,第二步抛异常,事务必须回滚,数据库不能凭空多钱。Spring声明式事务用起来很简单——方法上标@Transactional,但坑也在这几个位置:事务只对公共方法生效,同类内部调用不生效,异常被吞了不生效,加锁和事务混用可能会死锁。我建议每个新人都在本地故意制造一次事务不生效的场景,亲眼看数据错乱,以后才不会在配置上草率。
3.4 Spring Security:权限设计从登录开始
很多人看到Spring Security的过滤器链就头大,包括我自己当年也是。但换个角度想,安全本来就是复杂的:你得知道“你是谁”(认证),得知道你“能干什么”(授权),还得保证这些判断不被篡改(加密与Token)。Spring Security只是把这些步骤标准化了,所以你不该绕过它,应该感谢它有标准实现。
最简单的贴合实战路径是这样的:第一步,引入spring-boot-starter-security,启动后访问任何页面,它都会弹出默认登录框,说明认证过滤器已经在工作。第二步,自定义UserDetailsService,从数据库里查用户并比对密码,把默认用户替换掉。第三步,用SecurityFilterChain配置放行路径,比如登录接口和注册接口放行,其余接口必须认证。第四步,接上JWT或OAuth2,把无状态登录做出来。当你走到第四步,就碰到了Spring Security OAuth2 Authorization Server这个热词,它本质上是帮你搭建一个现成的授权服务器,用来发放Token和管理客户端授权,适合公司内部多系统统一登录的场景。
这个阶段我对新人有句忠告:不要一开始就追求把所有请求都拦截,也不要在还不理解Session机制的时候直接用JWT。先跑通默认流程,再逐步放开,安全框架最忌讳一步到位。
4. 实操现场:一次“登录注册模块”从零到能跑
4.1 环境搭建一直在翻车?先看这里
动手写代码前,环境问题已经能劝退一半人。“IDEA为什么创建不了Spring项目”是一个高频搜索词,其实原因就那么几个:第一,IDEA里的Spring Initializr需要联网,网络不通时创建向导直接失败;第二,JDK版本和Spring Boot版本不匹配,比如Spring Boot 2.x对JDK 17的兼容性就有坑;第三,Maven配置有问题,仓库地址没配好,依赖下载卡住。我的建议是,先打开IDEA的Settings确认Maven指向了阿里云镜像,再确认JDK版本,这样大概率能解决。
如果你用的是VS Code,也不是不能写Spring Boot,装上Spring Boot Extension Pack和Java Extension Pack,一样能通过start.spring.io生成工程。VS Code的优点是轻量,缺点是自动提示和调试体验还是比IDEA差一截,一台内存不够的笔记本上操作会更流畅。我日常是IDEA为主,VS Code当快速预览编辑器用,两个都不冲突。
创建工程时,推荐直接访问start.spring.io生成压缩包,选好Spring Web、MyBatis、MySQL Driver、Validation、Lombok这些依赖,下载解压后用IDEA打开。这里有个细节:生成的groupId和artifactId会决定包路径,建议一次性改成你习惯的公司域名倒写形式,比如com.example.mall,免得后面移动包名时一地鸡毛。
4.2 后端接口与关键配置,一步步落地
登录注册模块的后端,我按下面的顺序搭,最顺手。
第一,在application.yml里配置数据源和MyBatis。数据源配置拼写最容易错,我贴一份精简配置供参考:
spring: datasource: url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: truemap-underscore-to-camel-case这个配置我建议一直开着,否则数据库字段下划线和Java驼峰字段对不上,结果集里全是null。
第二,写User实体和UserMapper。实体字段对应数据库表的id、username、password、nickname、create_time。Mapper接口写三个方法:根据用户名查用户、插入用户、根据ID查用户。对应XML写成三个简单SQL,注意插入时密码字段要传加密后的密文。
第三,写注册逻辑。注册接口收到username和password后,先查一次用户名是否存在,存在就返回“用户名已占用”;不存在则用BCrypt加密密码再入库。这里建议引入validation依赖,用自定义校验注解校验密码强度、用户名合法性,正好把“Spring自定义Validate”练一遍。实现方式就是写一个注解加一个ConstraintValidator,在注解上指定校验逻辑类,使用的时候在Controller参数上加@Validated触发校验。
第四,写登录逻辑。登录时按用户名查出用户,用BCrypt的matches方法比对密码明文和密文,匹配成功则生成一个Token返回给前端。Token可以简单用UUID,也可以引入JWT带上用户ID和过期时间。我自己的项目从UUID过渡到JWT,原因是JWT能塞业务信息,后端不用存会话状态,适合后面接Spring Cloud。
第五,写一个拦截器,校验除注册、登录外的所有接口必须携带合法Token。实现HandlerInterceptor,在preHandle方法里从Header取Token,解析成功就放行,失败就返回401。注册Interceptor时要排除掉登录和注册两个路径,否则项目一启动就自己把自己拦住。
这套代码跑通之后,你自己就拥有了一个小型可复用的用户模块,后续做任何商城、后台、公司项目,都能直接把这张皮扒过去用。
4.3 前端联动:Vue登录状态,别踩跨域坑
前端用Vue,我只需要你关注三件事。第一,axios实例的封装:baseURL指向后端地址,请求拦截器里从localStorage取出Token塞进Authorization头。第二,路由守卫:router.beforeEach里判断,如果访问需要登录的页面且没有Token,就跳转到登录页。第三,响应拦截器:后端返回401时,统一清除本地登录态并跳回登录页。
跨域是最常见的拦路虎。前后端分离开发时,前端跑在5173端口,后端跑在8080端口,浏览器会拦截后端返回的响应。解决办法是后端加一个CORS配置,允许指定的前端来源和请求头。
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }这里要注意,allowCredentials(true)和allowedOrigin(“”)在一起时浏览器会直接罢工,所以要用allowedOriginPattern("")。这个坑我当年查了大半天,最后发现只是配置写法不对。
5. 学习路上的坑与排查思路
5.1 新手翻车排行榜,我几乎全见过
第一坑是依赖冲突。Spring全家桶版本家族庞大,一不小心就出现两个包各自引入不同版本的第三方库,典型表现是启动报NoSuchMethodError或ClassNotFoundException。解决办法是统一用Spring Boot的BOM管理版本,子模块不要随意写版本号,大局观要拉满。
第二坑是循环依赖被滥用。我曾经见过一个项目,Service层互相依赖绕成了一个环,Spring三级缓存把项目救回来了,但每个人改代码都胆战心惊。循环依赖能解决但很丑,建议通过构造器注入的方式从设计上避免,或者把公共逻辑抽到第三层。
第三坑是事务不生效。最常见的是同类里的方法互调,比如save方法里调用this.doSave,事务注解标在doSave上,但this调用不走代理,事务自然失效。解决方法是注入自身代理或把逻辑拆到另一个Bean里。
第四坑是日志切面重复记录。一个方法被多个切面匹配时,日志会重复打印。排查方法很简单,把切点表达式打印出来看看重叠范围,或者给不同切面设置@Order控制顺序。
第五坑是配置文件堆成一坨。application.yml上千行谁都受不了,按功能拆分就变成application-db.yml、application-redis.yml,再通过spring.profiles.active把它们组装起来。这个习惯从第一个项目就该养成。
5.2 “怎么查看Spring AOP有没有启用”的排查现场
这个热词对应的场景,多半是切面没生效。我的排查顺序如下。
第一步,确认依赖。pom里有没有spring-boot-starter-aop,这是最容易被忽略的,且Spring Boot默认不会自动带AOP。
第二步,确认注解。切面类上有没有@Aspect和@Component,Spring容器认不认你这个Bean。
第三步,确认切点表达式。execution(* com.example.service..(..))的包路径是不是写错了。很多人把service写成了services,一错就错一下午。
第四步,确认目标方法是public且非final。JDK动态代理和CGLIB都代理不了private方法,final方法也够呛。
第五步,观察启动日志或断点。在切面方法上打断点,请求如果进来了说明切面已生效,没进来则倒回前三步查。也可以临时写一个切面,在@Around里打印一行“AOP IS WORKING”,看控制台有没有输出。
这套流程半小时内能解决八成AOP问题,我建议你把它存成自己的排查清单,比网上搜零散回答高效得多。
5.3 源码、视频、PDF,资料到底怎么选
网上搜“Spring全家桶”会得出海量资料,但质量参差不齐。我的原则是:源码能看官方就看官方,英文不好可以配合中文社区翻译。视频选“案例驱动型”,凡是标题写着“三小时学完”的,一律不看,因为那种视频只能让你“眼熟”,无法让你“会做”。PDF也不是不行,但像“Spring Cloud微服务快速上手PDF”这种,你看完只能记住目录,真要上手还需要跟着代码敲一遍。
开源源码的正确用法是“带着问题看”,不是直接跑起来。比如你搜索“基于Spring Boot + MyBatis的多商户跨境商城源码”,下载之后先看pom依赖,梳理哪些组件是核心,再看数据库脚本,搞清楚表结构,最后看一个核心业务链路怎么从前端走到SQL。这样读一遍比你下载十个项目放着吃灰有用得多。
官方文档最该读的是Spring Boot Reference Documentation的“Core Features”章节,以及Spring Framework的“Core”章节。其余内容等踩坑遇到再看,毕竟成年人学技术的时间,得花在刀刃上。
6. 关于学习节奏的几句实在话
6.1 输出是检验学习的唯一标准
这行最不缺的就是“看起来会了”的人。我在实际带新人时发现,把学到的Spring知识讲给别人听,或者写成笔记,效果比闷头看视频好十倍。你可以在公司内部做一个半小时分享,主题就叫“Spring三级缓存到底在缓存什么”,如果能讲明白别人提出的问题,你是真的掌握了;如果讲得卡壳,卡住的地方就是你该补的知识盲区。
我自己的习惯是,每学一个组件,就做一个小demo放进自己的工具箱仓库。Spring Boot集成MyBatis是一个demo,Spring Security默认登录是一个demo,Spring StateMachine做一个订单状态机是一个demo。下次做正式项目时,直接翻自己的demo,比重新查文档快得多。
6.2 别和别人比进度,Spring全家桶是长跑不是冲刺
我见过有人两周学完Spring Boot,也见过有人三年还在反复看IOC,最后都能找到工作,区别在于前者知道自己在学什么,后者只是被焦虑推着走。一个合理的节奏是:第一个月死磕Spring Framework和手写小型IOC/AOP,第二个月做登录注册模块,第三个月接触Spring Security和数据事务,第四个月再碰Spring Cloud。每个阶段做一个能运行的项目,比“看完十本PDF”有价值得多。
如果非要说一个最重要的心法,那只有一句:把“Spring到底帮我做了什么”这个问题,永远挂在嘴边。等你在学习或排查问题时,能下意识回答出这个问题,Spring全家桶对你来说就算真正入门了。这个标准是我带人时一直用的,也是我判断自己有没有学会一门框架的核心方法。