首页
壁纸
统计
友链
Search
1
Vue2详细笔记
68 阅读
2
ExpressAPI
34 阅读
3
微信小程序
31 阅读
4
Spring MVC 请求生命周期
30 阅读
5
Nestjs概述-中文
29 阅读
Nodejs
Vue
Java
Msql
登录
Search
Wasnl
累计撰写
40
篇文章
累计收到
1
条评论
首页
栏目
Nodejs
Vue
Java
Msql
页面
壁纸
统计
友链
搜索到
9
篇与
的结果
2026-07-07
Java接口(Interface)与抽象类(Abstract Class)
这是一份为你定制的Java接口(Interface)与抽象类(Abstract Class)终极对比笔记。这份笔记整合了从Java 7到Java 17的所有语法变迁,并深入到设计哲学和底层JVM机制,适合面试冲刺或作为案头速查手册。📌 第一部分:核心定义(先定调)抽象类(Abstract Class):“不完整的实体”。它用来描述一类事物公共的“本质”(状态+行为)。它可以有构造器、有属性、有已实现的方法,但因为不够具体,所以不允许被new出来。接口(Interface):“纯粹的契约/能力”。它用来定义一种“行为规范”。它不管实现者是谁(可以是鸟、飞机、超人),只要签署了这份契约(implements),就必须具备这个能力。📌 第二部分:终极语法速查表(Java 8+ 特别版)对比维度抽象类(Abstract Class)接口(Interface)关键字abstract classinterface实例化(new)不能(无法创建对象)不能(无法创建对象)构造方法可以有(用于子类初始化父类属性)绝对没有(因为无实例变量需初始化)成员变量可以是任何类型(private/protected/public 实例变量,可以有状态)默认且只能是 public static final(常量),变量必须显式赋初值普通具体方法可以有(直接写带{}的方法体)Java 8+ 通过 default 和 static 可以有;Java 9+ 通过 private 可以有抽象方法使用 abstract 关键字,子类必须实现(除非子类也是抽象类)默认隐含 public abstract,实现类必须实现(除非实现类是抽象类)继承/实现关系单继承(一个类只能 extends 一个父类)多继承/多实现(一个接口可以 extends 多个接口;一个类可以 implements 多个接口)访问修饰符限制方法可以是 public/protected/private/default接口中的抽象方法隐含且只能是 public(不能是private或protected,否则编译报错)静态方法可以有,子类可以继承调用可以有(Java 8+),但只能通过接口名调用,实现类无法继承final 修饰可以有 final 方法(禁止子类重写)接口中的方法不能声明为 final(因为抽象/默认方法天生需要被重写或覆盖)📌 第三部分:方法家族全览(最易混淆点详解)接口到底能写哪些方法?这是面试高频扣分点:方法类型是否允许(接口)是否允许(抽象类)备注抽象方法(无方法体)✅ 允许(隐含public abstract)✅ 允许接口只干这事(Java 7之前)实例具体方法(有方法体)❌ 不允许(直到Java 8)✅ 允许抽象类主打的功能default 方法(Java 8+)✅ 允许—用于接口版本升级,避免老实现类报错static 方法(Java 8+)✅ 允许✅ 允许接口的static不可继承;抽象类的static可被子类继承调用private 方法(Java 9+)✅ 允许✅ 允许接口内用于抽取default方法的公共逻辑,不对外暴露📌 第四部分:设计哲学(本质区别,面试必答)抽象类:本质是“是什么”(Is-A)。侧重于对象本身。子类和父类必须有血缘关系(例如:Dog extends Animal)。用于捕获公共的状态(属性)和通用的基础逻辑。例子:所有订单都有订单号、金额,创建时都要打印日志。这些状态和步骤必须由抽象类来定义,接口做不到。接口:本质是“能做什么”(Can-Do / Like-A)。侧重于对象拥有的能力。完全不相关的类可以通过实现同一个接口获得相同能力(例如:Bird、Plane、Superman 都能实现 Flyable)。用于定义行为契约,不关心实现者的内部状态。例子:Comparable(可比较)、Runnable(可运行)、Serializable(可序列化)。📌 第五部分:经典协作模式(源码级的黄金搭档)在顶级框架(如Spring、JDK集合框架)中,它们从不“单打独斗”,而是按照 “接口定义标准 + 抽象类提供骨架 + 具体类实现业务” 三层结构配合: [List 接口] ← 定义契约(能添加、能删除、能遍历) ↑ (implements) [AbstractList 抽象类] ← 提供骨架(把 indexOf、equals 等通用逻辑先写一半) ↑ (extends) ┌──────────┴──────────┐ [ArrayList] [LinkedList] ← 具体实现(各自实现最核心的差异化逻辑)结论:用接口应对多态和扩展,用抽象类应对代码复用和封装状态。📌 第六部分:面试高频陷阱题(查漏补缺)抽象类能实现接口吗? ✅ 可以。且抽象类实现接口时可以不实现接口的方法,留给具体子类去实现(这就是适配器模式的底层原理)。接口能继承抽象类吗? ❌ 绝对不可以。接口只能 extends 接口,不能 extends 类(语法上禁止)。什么时候用 default 方法重写? 一个类实现了两个接口,两个接口都有同名的 default 方法,此时实现类必须显式重写该方法,否则编译冲突。抽象类里的 static 方法和接口里的 static 方法区别? 抽象类的 static 方法可以通过子类名直接调用(继承);接口的 static 方法只能通过接口名调用,子类/实现类无法继承。📌 第七部分:极简决策脑图(实用场景)如果你的需求是: ├── 共享给子类公共的 属性(成员变量)? │ └── 是 → 必须用 抽象类(接口存不住状态) ├── 需要 非public 的访问权限(protected/private)? │ └── 是 → 必须用 抽象类 ├── 想要为 完全无关的类 提供通用能力(如序列化)? │ └── 是 → 必须用 接口 ├── 想要利用 多重继承 的好处? │ └── 是 → 必须用 接口 └── 想要为已有系统做功能增强(不破坏旧代码)? └── 是 → 用接口的 default 方法(Java 8+)这份笔记涵盖了从语法到架构的全部精髓。如果你想基于这份笔记,手写一个“接口+抽象类”配合的实际Demo(比如模拟Spring的BeanFactory),我可以立刻给你写一份,让你彻底吃透它们的配合使用。😊
2026年07月07日
3 阅读
0 评论
0 点赞
2026-07-07
数组操作
在 Spring Boot 2.7 的企业实际开发中,数组操作主要依赖 Java 标准库(java.util.Arrays)和 Spring 框架内置工具类(org.springframework.util 包),两者结合基本能覆盖所有场景。⚙️ 数组操作核心方法速查操作类型核心方法所属类/库关键说明排序Arrays.sort(array)java.util.Arrays对数组进行原地升序排序。二分查找Arrays.binarySearch(array, key)java.util.Arrays必须在已排序数组中使用。数组拷贝Arrays.copyOf(original, newLength)Arrays.copyOfRange(original, from, to)java.util.Arrays灵活复制数组全部或部分内容。数组填充Arrays.fill(array, value)java.util.Arrays将数组所有或指定范围元素设为同一个值。数组转字符串Arrays.toString(array)Arrays.deepToString(array)java.util.Arrays方便打印一维或多维数组内容。数组比较Arrays.equals(array1, array2)Arrays.deepEquals(array1, array2)java.util.Arrays比较一维或多维数组内容是否相等。集合判空CollectionUtils.isEmpty(collection)CollectionUtils.isNotEmpty(collection)org.springframework.util.CollectionUtils安全地检查集合是否为 null 或空。数组转集合CollectionUtils.arrayToList(array)org.springframework.util.CollectionUtils支持基本类型数组转换。数组合并到集合CollectionUtils.mergeArrayIntoCollection(array, collection)org.springframework.util.CollectionUtils将数组元素合并到现有集合中。集合空值兜底CollectionUtils.emptyIfNull(collection)org.springframework.util.CollectionUtils如果集合为 null,返回一个空集合,避免 NPE。集合包含检查CollectionUtils.contains(collection.iterator(), element)org.springframework.util.CollectionUtils检查集合是否包含某元素。对象/数组判空ObjectUtils.isEmpty(obj)org.springframework.util.ObjectUtils可检查对象、数组、集合等是否为 null 或空。获取首个非空对象ObjectUtils.firstNonNull(obj1, obj2, ...)org.springframework.util.ObjectUtils从多个对象中返回第一个非 null 的。数组转分隔字符串StringUtils.arrayToCommaDelimitedString(arr)org.springframework.util.StringUtils将数组元素用逗号连接成字符串。🚀 数组与集合互转(高频场景)这是日常开发中最常见的操作之一,需要特别注意不同方法的区别。数组 转 ListArrays.asList(T... a):最常用,但返回的 List 是固定长度的,不能进行 add 或 remove 操作。且不支持基本类型数组。// 引用类型数组 -> 正确 String[] strArray = {"a", "b"}; List<String> list = Arrays.asList(strArray); // 基本类型数组 -> 错误! list 实际上是一个包含 int[] 对象的 List int[] intArray = {1, 2}; List<int[]> list = Arrays.asList(intArray); new ArrayList<>(Arrays.asList(array)):创建一个可变的 ArrayList,可以自由增删元素。String[] strArray = {"a", "b"}; List<String> list = new ArrayList<>(Arrays.asList(strArray)); list.add("c"); // 可以操作CollectionUtils.arrayToList(array):Spring 提供的工具方法,优雅地解决了基本类型数组的转换问题。int[] intArray = {1, 2}; // 自动将 int[] 转为 List<Integer> List<?> list = CollectionUtils.arrayToList(intArray); Arrays.stream(array).collect(Collectors.toList()):Stream 方式,灵活强大,适用于需要进行过滤、映射等复杂操作后再收集的场景。List 转 数组list.toArray(T[] a):标准推荐方式。List<String> list = Arrays.asList("a", "b"); // 传入一个长度相同的空数组,类型安全 String[] array = list.toArray(new String[0]);list.stream().toArray():Java 8 引入的 Stream 方式。List<String> list = Arrays.asList("a", "b"); String[] array = list.stream().toArray(String[]::new);✨ 高阶技巧:Stream 流式处理对于复杂的数组操作(过滤、转换、聚合),Stream API 是首选。int[] numbers = {1, 2, 3, 4, 5}; // 1. 过滤出偶数并打印 Arrays.stream(numbers).filter(n -> n % 2 == 0).forEach(System.out::println); // 输出 2, 4 // 2. 所有元素乘以2并收集为新的List List<Integer> doubledList = Arrays.stream(numbers) .map(n -> n * 2) .boxed() // 将 IntStream 装箱为 Stream<Integer> .collect(Collectors.toList());对于二维数组,Arrays.stream(arr) 得到的是 Stream<int[]>,即每一行作为一个元素。🧰 企业常用第三方库虽然标准库和 Spring 工具类已很强大,但在实际项目中,为了进一步简化代码、减少样板代码,往往会引入一些优秀的第三方库:Hutool:国产明星工具库,提供 ArrayUtil 等大量实用的数组操作方法。Guava:Google 出品,其 Lists、Ints 等工具类在集合和数组操作上非常强大。Apache Commons Lang:老牌工具库,提供 ArrayUtils 类。这些库通常提供了更丰富、更便捷的API,例如判空、反转、合并等,可以作为补充。⚠️ 踩坑指南Arrays.asList() 的“坑”:返回的是 java.util.Arrays.ArrayList,不是我们常用的 java.util.ArrayList,不支持 add/remove 操作,否则会抛出 UnsupportedOperationException。基本类型数组的误用:如 Arrays.asList(new int[]{1,2}),得到的是一个 List<int[]>,而非 List<Integer>。空指针异常 (NullPointerException):当数组或集合为 null 时,直接操作或遍历会抛出 NPE。建议使用 Spring 的 CollectionUtils.isEmpty()或 ObjectUtils.isEmpty()进行安全检查。数组越界 (ArrayIndexOutOfBoundsException):访问数组时,索引必须在 [0, array.length - 1] 范围内。遍历时优先使用增强 for 循环或 Arrays.stream() 来避免手动管理索引。💎 总结Spring Boot 2.7 企业开发中的数组操作,核心是掌握 java.util.Arrays 和 org.springframework.util 包下的工具类。对于数组与集合的转换、判空等高频操作,优先使用 Spring 的 CollectionUtils,可以避免很多常见的坑。对于复杂的业务逻辑,善用 Stream API 能让代码更清晰、更优雅。
2026年07月07日
2 阅读
0 评论
1 点赞
2026-06-10
Spring MVC 知识地图
🌐 Spring MVC 知识地图一、核心架构与组件Spring MVC 核心 ├── DispatcherServlet(前端控制器) ├── HandlerMapping(处理器映射) │ ├── RequestMappingHandlerMapping (注解映射,最常用) │ ├── BeanNameUrlHandlerMapping │ └── SimpleUrlHandlerMapping ├── HandlerAdapter(处理器适配器) │ ├── RequestMappingHandlerAdapter │ ├── HttpRequestHandlerAdapter │ └── SimpleControllerHandlerAdapter ├── Handler / Controller(处理器) ├── ModelAndView(模型与视图封装) ├── ViewResolver(视图解析器) │ ├── InternalResourceViewResolver(JSP) │ ├── BeanNameViewResolver │ ├── XmlViewResolver │ ├── ContentNegotiatingViewResolver │ └── …… └── View(视图) ├── JSP / JSTL ├── Thymeleaf ├── FreeMarker └── ……二、请求处理完整流程客户端请求 → DispatcherServlet 接收 ├── 1. 通过 HandlerMapping 查找 Handler(返回 HandlerExecutionChain,包含拦截器) ├── 2. 通过 HandlerAdapter 执行 Handler(Controller) ├── 3. Handler 执行业务逻辑,返回 ModelAndView ├── 4. 通过 ViewResolver 解析 ModelAndView 得到 View 对象 └── 5. View 渲染,将模型数据填充到视图,生成响应三、控制器开发Controller 开发 ├── 注解 │ ├── @Controller / @RestController │ ├── @RequestMapping │ │ ├── @GetMapping │ │ ├── @PostMapping │ │ ├── @PutMapping │ │ ├── @DeleteMapping │ │ └── @PatchMapping │ └── @CrossOrigin(跨域) ├── 请求参数绑定 │ ├── @RequestParam │ ├── @PathVariable(路径变量) │ ├── @RequestHeader │ ├── @CookieValue │ ├── @MatrixVariable │ ├── @RequestBody(JSON/XML 等) │ ├── @ModelAttribute(表单/查询参数绑定到对象) │ ├── HttpServletRequest / HttpServletResponse │ └── MultipartFile(文件上传) ├── 返回类型 │ ├── String(视图名,配合 Model) │ ├── ModelAndView │ ├── void(直接操作 HttpServletResponse) │ ├── @ResponseBody / ResponseEntity(JSON/XML 响应) │ └── View、Model、Map 等 └── 异步处理 ├── Callable<T> ├── DeferredResult<T> └── ResponseBodyEmitter / SseEmitter / StreamingResponseBody四、数据绑定、类型转换与校验数据绑定与校验 ├── 类型转换 │ ├── PropertyEditor │ ├── Converter / ConverterFactory │ ├── Formatter(日期/数字等格式化) │ └── @InitBinder(自定义绑定规则,注册编辑器/校验器) ├── 数据校验 │ ├── JSR-380(Bean Validation):@Valid / @Validated │ ├── BindingResult / Errors(校验结果) │ └── 自定义校验注解 └── WebDataBinder └── 控制绑定行为(允许/禁止字段等)五、RESTful Web 服务REST 支持 ├── @RestController = @Controller + @ResponseBody ├── HTTP 方法映射注解 ├── 内容协商 ContentNegotiationManager ├── HttpMessageConverter 消息转换器 │ ├── MappingJackson2HttpMessageConverter(JSON) │ ├── Jaxb2RootElementHttpMessageConverter(XML) │ ├── StringHttpMessageConverter │ └── FormHttpMessageConverter 等 ├── 请求/响应体处理 │ ├── @RequestBody │ └── @ResponseBody / ResponseEntity / HttpEntity ├── 跨域 @CrossOrigin / 全局 CORS 配置 └── HATEOAS 支持(Spring HATEOAS)六、视图解析与渲染视图技术 ├── JSP + JSTL │ └── InternalResourceViewResolver 配置 ├── Thymeleaf │ └── SpringTemplateEngine + ThymeleafViewResolver ├── FreeMarker │ └── FreeMarkerViewResolver ├── 重定向与转发 │ ├── "redirect:/path"(RedirectView) │ └── "forward:/path"(InternalResourceView) ├── 视图解析链(多个 ViewResolver 顺序解析) └── ContentNegotiatingViewResolver(根据请求类型选择视图)七、拦截器与过滤器拦截器 HandlerInterceptor(Spring MVC 层面) ├── 方法 │ ├── preHandle(控制器执行前) │ ├── postHandle(控制器执行后,视图渲染前) │ └── afterCompletion(视图渲染后) ├── 配置方式 │ ├── XML 配置 <mvc:interceptors> │ └── Java 配置实现 WebMvcConfigurer.addInterceptors() └── 与 Servlet Filter 的区别 ├── Filter 在 Servlet 容器层面,不依赖 Spring └── Interceptor 可访问 Handler 对象、ModelAndView,更贴合 MVC八、异常处理异常处理体系 ├── @ExceptionHandler(方法级,仅处理当前 Controller) ├── @ControllerAdvice / @RestControllerAdvice(全局异常处理) │ └── + @ExceptionHandler、@InitBinder、@ModelAttribute ├── HandlerExceptionResolver 接口 │ ├── SimpleMappingExceptionResolver(映射异常到错误视图) │ ├── DefaultHandlerExceptionResolver(处理标准 Spring 异常) │ └── ResponseStatusExceptionResolver ├── @ResponseStatus(标注异常,返回对应 HTTP 状态码) └── 自定义异常 + 全局处理九、文件上传与下载文件操作 ├── 上传 │ ├── MultipartResolver │ │ ├── CommonsMultipartResolver(需 Apache Commons FileUpload) │ │ └── StandardServletMultipartResolver(Servlet 3.0+ 标准) │ └── @RequestParam("file") MultipartFile ├── 下载 │ ├── ResponseEntity<byte[]> 配合 InputStreamResource │ ├── StreamingResponseBody(流式大文件下载) │ └── 设置 Content-Disposition 响应头 └── 多文件上传(MultipartFile[] 或 List<MultipartFile>)十、国际化与主题i18n & 主题 ├── MessageSource(国际化消息源) │ ├── ResourceBundleMessageSource │ └── ReloadableResourceBundleMessageSource(可热加载) ├── LocaleResolver(区域解析器) │ ├── AcceptHeaderLocaleResolver │ ├── SessionLocaleResolver │ ├── CookieLocaleResolver │ └── FixedLocaleResolver ├── LocaleChangeInterceptor(切换语言拦截器) ├── 主题 Theme │ ├── ThemeResolver │ └── ThemeSource(ResourceBundleThemeSource)十一、配置方式配置方式演进 ├── XML 时代 │ ├── web.xml 配置 DispatcherServlet │ ├── [name]-servlet.xml 配置 │ ├── <mvc:annotation-driven/> │ ├── <mvc:resources>(静态资源处理) │ └── <mvc:view-controller>(无逻辑视图跳转) ├── Servlet 3.0+ 纯 Java 配置 │ ├── WebApplicationInitializer / AbstractAnnotationConfigDispatcherServletInitializer │ ├── @Configuration + @EnableWebMvc │ ├── 实现 WebMvcConfigurer 接口进行定制 │ └── 静态资源 addResourceHandlers() └── Spring Boot 自动配置 ├── spring-boot-starter-web ├── 自动配置 DispatcherServlet、HttpMessageConverters、ViewResolver 等 ├── application.properties / yml 微调 └── 使用 @Configuration + WebMvcConfigurer 扩展十二、测试支持测试 ├── MockMvc(独立测试控制器,不启动完整服务器) │ ├── mockMvc.perform(get("/api")) │ ├── .andExpect(status().isOk()) │ └── .andExpect(jsonPath("$.name").value("test")) ├── @WebMvcTest(Spring Boot 切片测试,仅加载 MVC 层) ├── TestRestTemplate / WebTestClient(集成测试) └── Mock 服务依赖(@MockBean)十三、高级与周边高级特性 ├── CORS 全局配置(WebMvcConfigurer.addCorsMappings) ├── HTTP 缓存控制(CacheControl, ETag, Last-Modified) ├── Servlet 异步支持 / 响应式桥梁 ├── WebSocket 集成(@MessageMapping, SimpMessagingTemplate) ├── Swagger / OpenAPI 3 文档生成 ├── 多版本 API 管理 └── 自定义 HandlerMethodArgumentResolver / HandlerMethodReturnValueHandler如果需要某个分支更详细的逐层展开,或想看 Spring MVC 与 Spring Boot 整合的实例脑图,可以告诉我。
2026年06月10日
6 阅读
0 评论
1 点赞
2026-06-10
Spring MVC 请求生命周期
Spring MVC 请求生命周期SpringBoot 2.7 + Java8 企业级开发一、整体架构图 —— 一次请求的完整流水线HTTP Request -> http://你的项目/getUser?id=1 │ ▼ ┌─────────────────────┐ │ Tomcat │ 内嵌 Servlet 容器,最早接收请求 │ Servlet Container │ └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ Filter 过滤器链 │ Servlet 级别的“门卫”,工作在 Spring MVC 之前 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ DispatcherServlet │ Spring MVC 的“总控”,分发请求的核心 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ HandlerInterceptor │ Spring 自己的拦截器,更懂 Controller │ preHandle │ 请求到达 Controller 前执行 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ Controller │ 你写的接口,@RestController / @GetMapping └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ Service │ 业务逻辑层 └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ DAO/JdbcTemplate │ 数据访问层,执行 SQL └─────────────────────┘ │ ▼ ┌─────────────────────┐ │ MySQL │ 数据库 └─────────────────────┘ │ ▼ Controller返回结果 返回 Java 对象 │ ▼ Interceptor.postHandle 所有拦截器的 postHandle │ ▼ ViewResolver / JSON序列化 前后端分离时转成 JSON 字符串 │ ▼ Interceptor.afterCompletion 资源清理、日志记录 │ ▼ Response → 浏览器二、企业项目真实执行顺序(必背)虚假的顺序:Tomcat -> Interceptor -> Controller实际严格顺序:Tomcat -> Filter -> DispatcherServlet -> Interceptor -> Controller -> Service -> DAO -> MySQL为什么是这个顺序?Filter 是 Servlet 规范 定义的,工作在容器级别,比 Spring 更底层;Interceptor 是 Spring MVC 内部 的,只有在 DispatcherServlet 接收请求之后才生效。也就是说:Filter 可以拦截所有请求(包括静态资源),而 Interceptor 只能拦截进入 Spring MVC 的请求。三、Filter 和 Interceptor 区别 —— 两个不同级别的“保安”1. Filter(Servlet 级别)定义方式:实现 javax.servlet.Filter 接口执行时机:Tomcat → Filter → Spring MVC特点:工作在容器层,不依赖 Spring,拿不到 Controller、方法等 Spring 上下文信息。典型用途:JWT 登录校验(直接解析 token,失败直接返回 401)XSS 过滤(清洗 <script> 等危险字符)请求日志(记录每个请求的耗时、URL)跨域处理(CorsFilter 统一设置响应头)2. Interceptor(Spring MVC 级别)定义方式:实现 org.springframework.web.servlet.HandlerInterceptor 接口执行时机:DispatcherServlet → Interceptor → Controller特点:能获取到 Handler(Controller 方法)、参数、返回结果等,是 Spring 生态内的拦截手段。典型用途:用户信息注入(从 token 解析用户信息,放入 UserContext)权限校验(admin / user 角色判断)操作日志(记录“谁在何时做了什么”)API 访问统计(PV / UV 计数)面试标准答案Filter 先执行,Interceptor 后执行。 Filter 是 Servlet 规范,Intercetpor 是 Spring MVC 专属。四、DispatcherServlet 到底干了什么 —— 核心方法 doDispatch()设计模式:前端控制器模式(Front Controller Pattern)所有请求都会先被 DispatcherServlet 接管,它自己不干活,只负责指挥。源码简化流程:doDispatch() { // 1. 根据请求找到 Handler(Controller 方法)并包装成 HandlerExecutionChain HandlerExecutionChain chain = getHandler(request); // 2. 执行所有拦截器的 preHandle chain.applyPreHandle(request, response); // 3. 真正调用 Controller 方法 HandlerAdapter adapter = getHandlerAdapter(handler); ModelAndView mv = adapter.handle(request, response, handler); // 4. 执行所有拦截器的 postHandle chain.applyPostHandle(request, response, mv); // 5. 处理返回结果(JSON 序列化、视图渲染等) processDispatchResult(request, response, chain, mv, exception); // 6. 触发拦截器的 afterCompletion(总是执行) chain.triggerAfterCompletion(request, response, exception); }五、HandlerExecutionChain —— Controller + 拦截器的组合体请求到达 DispatcherServlet 后,getHandler() 方法会将你的 Controller 方法和所有适用的拦截器打包成一个执行链。结构示意:HandlerExecutionChain ├── Handler(你的 Controller 方法) ├── Interceptor A ├── Interceptor B └── Interceptor C执行顺序(链式调用,具有栈特性):进入时:A.pre → B.pre → C.pre → Controller返回时:C.post → B.post → A.post最终完成:C.after → B.after → A.after(即使前面出异常也会执行)六、@RequestScope 的底层原理 —— 代理对象,而非每次都 new很多人以为 @RequestScope 每次请求都会创建一个全新的 Bean,实际上 Spring 注入的是一个代理对象。特别提醒:代理对象通过当前线程的 ThreadLocal 拿到绑定的请求上下文,从而找到属于当前请求的那个真实 @RequestScope 实例。如果在 Controller 里用 @Async 等开了新线程,原请求的 ThreadLocal 会丢失,导致代理找不到请求上下文而直接报错。@Autowired private UserContext userContext;实际注入的是 UserContext$$SpringProxy 代理类。该代理对象内部并不持有真实数据,当真正调用其方法时,它会从当前请求的 RequestAttributes 中动态获取属于当前请求的真实实例。流程:当前线程 → RequestAttributes → 真实的 UserContext好处:即便 Controller 是单例(Singleton),也能安全地使用 @RequestScope 的 Bean,因为每次调用都会通过代理去获取当前请求对应的真实对象。七、ThreadLocal 与 @RequestScope —— 如何安全地存放用户信息在企业项目中,经常需要在任何地方(Service、DAO)获取当前登录用户,常用两种方案。方案实现方式优点缺点最佳实践ThreadLocalUserHolder.set(user) / UserHolder.get()极快,线程隔离必须手动 remove(),否则线程池复用时会内存泄漏或数据串人在拦截器的 afterCompletion 中清理@RequestScope注解在 Spring 管理的 Bean 上Spring 自动管理生命周期,请求结束自动销毁,无泄漏风险性能比 ThreadLocal 多一点点反射/代理开销优先推荐,简单安全推荐:存放用户上下文信息时,优先选择 @RequestScope。只有在对性能要求极高、并发极大的场景下,才考虑 ThreadLocal,并确保在拦截器的 afterCompletion 中执行 remove()。八、Controller 参数解析过程 —— 为什么参数能自动绑定你写的 public Result get(Long id),Spring 能自动从请求里拿到 id,靠的是 HandlerMethodArgumentResolver 接口。该解析器会遍历判断当前参数是否能被自己解析,若能则从 request 中取值并绑定。常见注解与对应解析器:注解解析器@RequestParamRequestParamMethodArgumentResolver@PathVariablePathVariableMethodArgumentResolver@RequestBodyRequestResponseBodyMethodProcessor@RequestHeaderRequestHeaderMethodArgumentResolver例如:@RequestHeader("token") String token 背后就是 RequestHeaderMethodArgumentResolver 在干活。你也可以实现该接口并注册,来支持自定义的参数注入(比如自动注入当前登录用户对象)。九、JSON 如何变成 Java 对象 —— HttpMessageConverter前端发送 JSON:POST { "name":"Tom" }到后端自动变成 UserDTO 对象,核心组件是 HttpMessageConverter。默认使用的实现是 MappingJackson2HttpMessageConverter,底层依赖 Jackson。请求方向:请求体 JSON → Jackson 反序列化 → Java 对象 → Controller 参数响应方向:Controller 返回的 Java 对象 → Jackson 序列化 → JSON 字符串 → HTTP 响应因此 Jackson 是 Spring Boot 中处理 JSON 的事实标准,排查问题时经常要关注它。十、统一异常处理 —— 别再到处 try-catch在企业项目中,应使用 @RestControllerAdvice 进行全局异常拦截,避免在每个 Controller 方法中写重复的 try-catch。@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public Result handleException(Exception e) { log.error("系统异常", e); return Result.fail(e.getMessage()); } @ExceptionHandler(BusinessException.class) public Result handleBusinessException(BusinessException e) { return Result.fail(e.getCode(), e.getMessage()); } }执行流程:Controller 抛出异常 ↓ HandlerExceptionResolver 捕获 ↓ 找到匹配的 @ExceptionHandler 方法 ↓ 返回统一的错误响应这样 Controller 只需关注正常业务逻辑,所有异常都会流入全局处理器,返回规范的接口格式。十一、完整认证流程 —— 不要只相信 Token真正的安全认证绝不能只解析 token,而必须结合 Redis 等存储做二次校验。标准流程:1. 请求携带 JWT token 2. Interceptor 解析 token 得到 userId 3. 去 Redis 查询该 userId 对应的完整用户信息(含权限、状态) 4. 如果 Redis 中不存在或 token 已失效 → 直接返回 401 5. 将用户信息放入 UserContext(@RequestScope 管理的 Bean) 6. Controller 直接从 UserContext 获取用户信息,无需再解析 token为什么要加 Redis?Token 可能被伪造(弱签名或密钥泄露)用户可能已被管理员禁用,但 token 还未过期用户执行了“退出登录”,token 理应立刻失效总结:Token 只负责提供身份标识(userId),真正的用户资料和权限应从 Redis(或数据库)获取,并在请求上下文中传递。十二、Spring MVC 八大核心组件(高级理解)DispatcherServlet 只是总控,真正复杂的工作由这些组件完成:组件作用重要性HandlerMapping根据请求 URL 找到对应的 Handler(Controller 方法)★★★HandlerAdapter真正执行 Handler,适配不同类型的处理器★★★HandlerExceptionResolver处理异常,分发给 @ExceptionHandler 或 @ControllerAdvice★★★ViewResolver解析视图名,找到具体视图(前后端分离时用得少)★MultipartResolver处理文件上传请求★LocaleResolver国际化,解析客户端的语言/地区★ThemeResolver主题切换(老旧项目中常见)★FlashMapManager用于重定向时保存临时数据★其中最核心的三个:HandlerMapping、HandlerAdapter、HandlerExceptionResolver,理解它们才能真正把握 Spring MVC 的执行原理。总结 —— 一条线全部串起来完整请求处理链路:Tomcat → Filter(登录校验、XSS、日志、跨域) → DispatcherServlet → HandlerMapping(找到 Controller 方法) → HandlerInterceptor.preHandle(权限、用户注入) → HandlerAdapter(执行方法) → Controller → Service → DAO / JdbcTemplate → MySQL → (若有异常)HandlerExceptionResolver → @RestControllerAdvice 统一处理 → HttpMessageConverter(Java 对象 ↔ JSON) → HandlerInterceptor.postHandle / afterCompletion → 返回 Response日常企业开发(SpringBoot 2.7 + JdbcTemplate + MySQL + Redis + JWT)中最核心的10个知识点:Filter — 容器层拦截,适合安全校验、跨域、日志Interceptor — Spring MVC 拦截,适合用户注入、权限、统计@RequestScope — 请求作用域 Bean,底层用代理实现ThreadLocal — 线程隔离的上下文存储,需手动清理HandlerMethodArgumentResolver — 参数解析器,实现自动注入HttpMessageConverter — JSON / 对象互转,底层 Jackson@RestControllerAdvice — 全局异常处理,不要到处 try-catchDispatcherServlet — 前端总控制器,调度所有请求HandlerExecutionChain — 拦截器与 Controller 的打包执行链Spring MVC 九大组件 — 理解项目架构离不开这些支撑组件
2026年06月10日
30 阅读
0 评论
2 点赞
2026-06-08
java
1. 策略模式 ⭐⭐⭐⭐⭐消灭 if-else 的核心武器,基于 Spring 容器自动选择策略。步骤:定义策略接口public interface Strategy { String getType(); void execute(); }实现多个策略并用 @Component 注册@Component public class StrategyA implements Strategy { @Override public String getType() { return "A"; } @Override public void execute() { /* ... */ } } @Component public class StrategyB implements Strategy { @Override public String getType() { return "B"; } @Override public void execute() { /* ... */ } }创建策略选择器@Component public class StrategySelector { private final Map<String, Strategy> strategyMap = new HashMap<>(); // 4. Spring自动注入所有Strategy实现到Map(详见文档末尾“注入条件”) public StrategySelector(Map<String, Strategy> strategyMap) { // 遍历注入的Map,按业务key重组 strategyMap.values().forEach(s -> this.strategyMap.put(s.getType(), s)); } // 5. 选择策略 public Strategy getStrategy(String type) { Strategy strategy = strategyMap.get(type); if (strategy == null) { throw new IllegalArgumentException("No strategy for: " + type); } return strategy; } }2. 工厂模式 ⭐⭐⭐⭐⭐创建对象的“万能工厂”,通过 Spring 容器自动装配产品族。步骤:定义产品接口public interface Product { String getType(); void doSomething(); }多个产品实现并注册@Component public class ProductA implements Product { @Override public String getType() { return "A"; } @Override public void doSomething() { /*...*/ } } @Component public class ProductB implements Product { @Override public String getType() { return "B"; } @Override public void doSomething() { /*...*/ } }创建工厂类(Spring自动注入所有产品)@Component public class ProductFactory { private final Map<String, Product> productMap; // 构造器注入:Spring会将所有Product的实现注入到Map中(key=bean名称,默认类名首字母小写) public ProductFactory(Map<String, Product> productMap) { this.productMap = productMap; } public Product create(String type) { Product product = productMap.get(type); // 或自定义getType()映射 if (product == null) throw new IllegalArgumentException("Unknown product type"); return product; } }与策略模式的区别:工厂侧重于创建/获取对象,策略侧重行为互换,但 Spring 集成写法相似。3. 责任链模式 ⭐⭐⭐⭐⭐多个处理器依次尝试,直到有人处理。步骤:定义请求上下文public class RequestContext { private boolean approved = false; private String rejectReason; private String approvedBy; // getters & setters... }编写 Handler 接口public interface Handler { boolean handle(RequestContext context); // true=处理完毕,不再传递 }具体处理器(@Component + @Order 控制顺序)@Component @Order(1) public class ManagerHandler implements Handler { public boolean handle(RequestContext context) { // 逻辑:通过则设置approved=true,返回true;否则返回false return true; } } @Component @Order(2) public class DirectorHandler implements Handler { /* ... */ }组装责任链(@PostConstruct 确保只排序一次)@Component public class HandlerChain { private final List<Handler> handlers; public HandlerChain(List<Handler> handlers) { this.handlers = handlers; } @PostConstruct public void init() { AnnotationAwareOrderComparator.sort(handlers); } public void process(RequestContext context) { for (Handler handler : handlers) { if (handler.handle(context)) break; } } }使用@Autowired HandlerChain chain; // ... RequestContext ctx = new RequestContext(); chain.process(ctx);4. 模板方法模式 ⭐⭐⭐⭐⭐父类定义骨架,子类填写细节。步骤:抽象模板类public abstract class AbstractExportService { public final void export() { prepareData(); writeFile(); cleanUp(); } protected abstract void prepareData(); protected abstract void writeFile(); protected void cleanUp() { /* 钩子:默认空实现 */ } }具体子类@Component public class ExcelExportService extends AbstractExportService { @Override protected void prepareData() { /*...*/ } @Override protected void writeFile() { /*...*/ } }Controller中使用(注入所有子类)@RestController public class ExportController { private final Map<String, AbstractExportService> exportServiceMap; // 注入时 key 为 bean 名称(类名首字母小写,或用@Service("excel")指定) public ExportController(Map<String, AbstractExportService> exportServiceMap) { this.exportServiceMap = exportServiceMap; } @GetMapping("/export/{type}") public void doExport(@PathVariable String type) { exportServiceMap.get(type).export(); } }5. 代理模式 ⭐⭐⭐⭐⭐控制对象访问,增强功能(Spring AOP 的基础)。Spring 推荐方式:声明式:@Transactional、@Cacheable 等本质是动态代理。手动示例:统计方法耗时。@Component public class SimpleService implements IService { @Override public void work() { /* ... */ } } @Component public class ServiceProxy implements IService { private final IService target; public ServiceProxy(@Qualifier("simpleService") IService target) { this.target = target; } @Override public void work() { long start = System.currentTimeMillis(); target.work(); System.out.println("cost: " + (System.currentTimeMillis() - start)); } }更常用的是直接使用 Spring AOP(@Aspect + @Around)实现动态代理。6. 状态模式 ⭐⭐⭐⭐⭐将状态逻辑拆分为独立的状态对象,避免大量 if-else。步骤(订单状态机):状态接口public interface OrderState { void pay(OrderContext ctx); void ship(OrderContext ctx); }具体状态@Component public class PendingPaymentState implements OrderState { public void pay(OrderContext ctx) { // 支付成功后切换状态 ctx.setState(ctx.getPaidState()); } public void ship(OrderContext ctx) { throw new UnsupportedOperationException(); } } // PaidState, ShippedState... 同理上下文持有状态@Component public class OrderContext { private OrderState current; // 注入所有状态 @Autowired private PendingPaymentState pendingPaymentState; @Autowired private PaidState paidState; //... getters/setters,初始化为 pendingPaymentState }Spring 中可使用状态枚举配合 Map<OrderStatus, OrderState> 自动注入。7. 观察者模式 ⭐⭐⭐⭐一对多通知,Spring 事件机制天然支持。步骤:定义事件public class OrderCreatedEvent extends ApplicationEvent { private final Long orderId; public OrderCreatedEvent(Object source, Long orderId) { super(source); this.orderId = orderId; } // getter }发布事件@Component public class OrderService { @Autowired private ApplicationEventPublisher publisher; public void createOrder() { // 业务... publisher.publishEvent(new OrderCreatedEvent(this, orderId)); } }监听事件(可使用 @EventListener 或 @TransactionalEventListener)@Component public class SendSmsListener { @EventListener public void handleOrderCreated(OrderCreatedEvent event) { // 发短信 } }8. 门面模式 ⭐⭐⭐⭐为复杂子系统提供统一入口,Service 层常见模式。示例: 下单门面聚合库存、支付、物流三个服务。@Component public class OrderFacade { @Autowired private InventoryService inventoryService; @Autowired private PaymentService paymentService; @Autowired private LogisticsService logisticsService; public void placeOrder(OrderDTO dto) { inventoryService.reduceStock(dto.getSku()); paymentService.charge(dto.getAmount()); logisticsService.scheduleDelivery(dto.getOrderId()); } }9. 装饰器模式 ⭐⭐⭐⭐动态附加责任,比继承更灵活。示例: 对数据读写组件增加缓存装饰器。public interface DataService { String read(); } @Component("basicDataService") public class BasicDataService implements DataService { /*...*/ } @Component public class CacheDecorator implements DataService { private final DataService delegate; public CacheDecorator(@Qualifier("basicDataService") DataService delegate) { this.delegate = delegate; } @Override public String read() { // 先查缓存,没有则调用delegate并缓存 return delegate.read(); } }10. 适配器模式 ⭐⭐⭐⭐兼容两个不匹配的接口,常用于整合外部系统。// 目标接口 public interface Logger { void log(String msg); } // 被适配的第三方类 public class ExternalLogLib { public void writeLog(String text) { /*...*/ } } // 适配器 @Component public class ExternalLogAdapter implements Logger { @Autowired private ExternalLogLib externalLogLib; @Override public void log(String msg) { externalLogLib.writeLog(msg); } }11. DDD(领域驱动设计) ⭐⭐⭐⭐⭐⭐聚焦核心业务复杂度,分层架构与战略设计。核心步骤(简化分层):用户接口层:Controller,接收请求并调用应用服务。应用层:@Service 应用服务,编排领域对象,不包含业务逻辑。领域层:实体(Entity)、值对象(Value Object)、聚合根(Aggregate Root)、领域服务(Domain Service)、仓储接口(Repository Interface)。基础设施层:仓储实现(@Repository),将聚合持久化到数据库。关键原则:领域层无任何 Spring 注解,纯 POJO。通过构造器注入将仓储接口注入领域服务或应用服务。聚合内通过根实体确保一致性。12. Event Driven(事件驱动架构) ⭐⭐⭐⭐⭐⭐通过事件解耦服务,提升伸缩性和最终一致性。Spring 实现:本地事件:ApplicationEventPublisher + @EventListener(见观察者模式)。分布式事件:集成 Kafka / RabbitMQ。// 发布领域事件到消息队列 @Autowired private KafkaTemplate<String, DomainEvent> kafkaTemplate; public void publish(DomainEvent event) { kafkaTemplate.send("topic-name", event); } // 消费 @KafkaListener(topics = "topic-name") public void handle(DomainEvent event) { /*...*/ }推荐配合 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) 保证事务提交后再发消息。13. Saga ⭐⭐⭐⭐⭐⭐分布式事务的最终一致性方案,通过协调正向/补偿操作。编排型 Saga(借助事件驱动):每个微服务监听前序事件,执行本地事务并发布新事件。若失败,发布补偿事件,上游监听并回滚。// 服务A发布订单创建事件,服务B监听并扣库存 // 若扣库存失败,服务B发布库存不足事件,服务A监听后进行补偿(取消订单)实现时可配合 Spring Cloud Stream / Axon Framework。14. CQRS(命令查询职责分离) ⭐⭐⭐⭐⭐⭐读写模型分离,最大化性能与扩展性。简单实现:命令侧:应用服务接收 Command,调用领域逻辑,写入主库。查询侧:@Service 直接从读库或缓存查询 DTO。// 命令 @PostMapping public void createOrder(@RequestBody CreateOrderCmd cmd) { commandService.handle(cmd); } // 查询(独立Controller或同一模块内分离) @GetMapping("/orders/{id}") public OrderView queryOrder(@PathVariable Long id) { return queryService.findById(id); }高级玩法:事件溯源,将所有状态变更存储为事件流,查询视图由事件投影构建。SpringBoot 2.7 注入条件(集合/Map注入)核心行为: Spring 会自动将所有实现了某个接口或父类的 Bean 注入到 List 或 Map 中。注入 List: @Autowired List<SomeInterface> list; 会按 Order 排序包含所有实现类的 Bean。注入 Map: @Autowired Map<String, SomeInterface> map; key 为 Bean 的名称(默认类名首字母小写,若用 @Service("myName") 则用指定名称),value 为实例。没有实现类时: Spring 默认会注入一个空集合(EmptyList/EmptyMap),不会报错。若希望强制存在才注入,可使用 @Autowired(required = true),但注入集合时 required=true 仍允许空集合,除非你将它用在非集合字段上。推荐方式: 构造器注入,显式声明 final 字段,避免 @Autowired 注解(Spring 4.3+ 单构造器自动注入)。@Component public class StrategySelector { private final Map<String, Strategy> strategyMap = new HashMap<>(); // 构造器注入:Spring 自动将所有的 Strategy 实现类注入 Map public StrategySelector(Map<String, Strategy> allStrategies) { allStrategies.values().forEach(s -> strategyMap.put(s.getType(), s)); } }在 Spring Boot 2.7 (Spring Framework 5.3.x) 下此行为完全稳定,完美支持策略/工厂等模式的自动装配。
2026年06月08日
8 阅读
0 评论
0 点赞
1
2