SpringBoot整合Redis-原理解析

管理员
# Spring Boot + Redis 配置深度解析:从注解到底层实现 ## 目录 1. [引言](#引言) 2. [代码整体架构分析](#代码整体架构分析) 3. [核心注解深度解析](#核心注解深度解析) 4. [Redis配置深度解析](#redis配置深度解析) 5. [依赖注入流程深度解析](#依赖注入流程深度解析) 6. [请求处理完整流程](#请求处理完整流程) 7. [框架底层工作总结](#框架底层工作总结) 8. [最佳实践建议](#最佳实践建议) 9. [总结](#总结) --- ## 引言 在Spring Boot开发中,Redis是一个常用的缓存和存储组件。本文将通过一个实际的Redis配置案例,深入分析Spring Boot框架的底层工作原理,包括各个注解的作用机制、Bean的创建流程、依赖注入的实现细节,以及HTTP请求的完整处理链路。 通过本文的学习,你将: - 理解Spring Boot核心注解的工作原理 - 掌握Redis配置的最佳实践 - 深入了解Spring的依赖注入机制 - 熟悉Spring MVC的请求处理流程 - 理解序列化机制的重要性 --- ## 代码整体架构分析 ### 1.1 三层职责划分 ``` ┌─────────────────────────────────────────────────────────────┐ │ 应用架构层次 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────┐ │ │ │ Controller层 │ ← GetKeyController │ │ │ (接口控制) │ 处理HTTP请求,调用Service │ │ └─────────────────┘ │ │ ↓ │ │ ┌─────────────────┐ │ │ │ Utils层 │ ← RedisUtil │ │ │ (工具封装) │ 封装Redis操作逻辑 │ │ └─────────────────┘ │ │ ↓ │ │ ┌─────────────────┐ │ │ │ Config层 │ ← RedisConfig │ │ │ (配置管理) │ 配置RedisTemplate和序列化器 │ │ └─────────────────┘ │ │ ↓ │ │ ┌─────────────────┐ │ │ │ Spring Data │ ← RedisTemplate │ │ │ Redis核心 │ 提供Redis操作API │ │ └─────────────────┘ │ │ ↓ │ │ ┌─────────────────┐ │ │ │ Redis服务器 │ │ │ └─────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### 1.2 核心代码文件 **配置层:RedisConfig.java** ```java @Configuration @PropertySource("classpath:redis.properties") public class RedisConfig { @Bean public RedisTemplate redisTemplate(RedisConnectionFactory factory) { // 配置RedisTemplate和序列化器 } } ``` **工具层:RedisUtil.java** ```java @Component public class RedisUtil { @Autowired private RedisTemplate redisTemplate; public Object get(String key) { // 封装Redis获取操作 } } ``` **控制层:GetKeyController.java** ```java @RestController public class GetKeyController { @Autowired private RedisUtil redisUtil; @RequestMapping("/getKey") public Object getKey(@RequestParam String key) { // 处理HTTP请求 } } ``` --- ## 核心注解深度解析 ### 2.1 @Configuration 注解 #### 2.1.1 底层原理 ```java /** * @Configuration 注解的底层实现机制 */ public class ConfigurationAnalysis { /** * 1. 注解定义 * * @Configuration 是一个复合注解,包含: * @Component:标记为Spring组件 * @Indexed:加速组件扫描 */ /** * 2. Spring处理流程 * * 步骤1:扫描阶段 * - ClassPathScanningCandidateComponentProvider 扫描类路径 * - 识别带有 @Configuration 的类 * - 将其注册为 BeanDefinition * * 步骤2:解析阶段 * - ConfigurationClassPostProcessor 处理配置类 * - 解析 @Bean、@Import 等注解 * - 生成 BeanDefinition * * 步骤3:代理创建 * - 如果不是 @Configuration(proxyBeanMethods = false) * - Spring会创建 CGLIB 代理 * - 确保@Bean方法的调用返回同一个实例 */ /** * 3. CGLIB代理示例 * * 原始方法: * public RedisTemplate redisTemplate() { ... } * * 代理方法(伪代码): * public RedisTemplate redisTemplate() { * // 检查Bean是否已存在 * if (beanFactory.containsBean("redisTemplate")) { * return beanFactory.getBean("redisTemplate"); * } * // 调用原始方法 * RedisTemplate template = super.redisTemplate(); * // 注册到容器 * beanFactory.registerSingleton("redisTemplate", template); * return template; * } */ } ``` #### 2.1.2 @Configuration vs @Component 对比 ```java /** * @Configuration vs @Component 对比 */ public class ConfigurationVsComponent { /** * @Configuration 特性: * 1. 生成CGLIB代理(默认) * 2. 保证@Bean方法的单例性 * 3. 支持配置类之间的依赖注入 * * @Component 特性: * 1. 不生成代理 * 2. 每次调用@Bean方法返回新实例 * 3. 简单的组件标记 * * 示例对比: * * @Configuration * class ConfigA { * @Bean public BeanA beanA() { return new BeanA(); } * @Bean public BeanB beanB() { return new BeanB(beanA()); } * // beanB中的beanA()和直接注入的beanA是同一个实例 * } * * @Component * class ConfigB { * @Bean public BeanA beanA() { return new BeanA(); } * @Bean public BeanB beanB() { return new BeanB(beanA()); } * // 每次调用beanA()都返回新实例! * } */ } ``` #### 2.1.3 源码核心类 ```java /** * @Configuration 源码核心类 */ public class ConfigurationSourceCode { /** * 核心处理类: * * 1. ConfigurationClassPostProcessor:配置类后处理器 * - 扫描@Configuration注解 * - 解析@Bean方法 * - 生成BeanDefinition * * 2. ConfigurationClassParser:配置类解析器 * - 解析配置类结构 * - 处理@Import、@ImportResource等 * * 3. ConfigurationClass:配置类元数据 * - 存储配置类信息 * - 包含@Bean方法列表 * * 4. CglibSubclassingInstantiationStrategy:CGLIB实例化策略 * - 创建配置类的代理对象 * - 拦截@Bean方法调用 */ } ``` --- ### 2.2 @Bean 注解 #### 2.2.1 底层原理 ```java /** * @Bean 注解的底层实现机制 */ public class BeanAnalysis { /** * 1. 注解属性详解 * * String name() default ""; // Bean名称 * String[] initMethod() default {}; // 初始化方法 * String[] destroyMethod() default {}; // 销毁方法 * Autowire autowire() default Autowire.NO; // 自动装配模式 * boolean primary() default false; // 是否为主要候选 * * 使用示例: * @Bean(name = "myRedisTemplate", initMethod = "init", destroyMethod = "cleanup") * public RedisTemplate redisTemplate() { ... } */ /** * 2. 方法参数注入机制 * * redisTemplate(RedisConnectionFactory factory) * * Spring如何找到 RedisConnectionFactory? * * 步骤1:解析参数类型 * - 通过反射获取方法参数类型:RedisConnectionFactory.class * * 步骤2:查找匹配Bean * - 在BeanFactory中查找类型匹配的Bean * - Spring Boot自动配置会提供 RedisConnectionFactory * * 步骤3:依赖注入 * - 通过@Autowired注解(隐式) * - 调用BeanFactory.getBean(RedisConnectionFactory.class) */ /** * 3. Bean注册流程 * * ConfigurationClassBeanDefinitionReader * ↓ * loadBeanDefinitionsForBeanMethod() * ↓ * 创建 BeanDefinition * ↓ * 设置 FactoryMethodName = "redisTemplate" * ↓ * 设置 FactoryBeanClass = RedisConfig.class * ↓ * 注册到 BeanDefinitionRegistry */ /** * 4. Bean实例化流程 * * ① 调用getBean("redisTemplate") * ② 查找BeanDefinition * ③ 创建Bean实例(通过CGLIB代理调用原始方法) * ④ 属性填充 * ⑤ 初始化回调(@PostConstruct) * ⑥ BeanPostProcessor后处理 * ⑦ 返回可用Bean */ /** * 5. Bean名称生成规则 * * 默认:方法名首字母小写 * redisTemplate() -> "redisTemplate" * * 自定义: * @Bean("customName") * public RedisTemplate redisTemplate() { ... } * * 多名称: * @Bean({"name1", "name2", "name3"}) */ } ``` #### 2.2.2 方法参数解析深度分析 ```java /** * @Bean 方法参数解析深度分析 */ public class BeanParameterInjection { /** * Spring支持多种参数注入方式: * * 1. 按类型注入 * @Bean * public RedisTemplate template(RedisConnectionFactory factory) { ... } * * 2. 按名称注入 * @Bean * public RedisTemplate template(@Qualifier("jedisConnectionFactory") * RedisConnectionFactory factory) { ... } * * 3. 按类型+多个参数 * @Bean * public RedisTemplate template(RedisConnectionFactory factory, * ObjectMapper mapper) { ... } * * 4. 直接值注入 * @Bean * public RedisTemplate template(@Value("${redis.timeout}") int timeout) { ... } * * 5. 可选注入 * @Bean * public RedisTemplate template(Optional factory) { ... } */ /** * 参数解析器实现原理 * * AutowiredAnnotationBeanPostProcessor * ↓ * determineCandidateConstructors() * ↓ * createArgumentArray() * ↓ * resolveDependency() * ↓ * DefaultListableBeanFactory.doResolveDependency() * ↓ * 根据类型查找Bean */ } ``` --- ### 2.3 @PropertySource 注解 #### 2.3.1 底层原理 ```java /** * @PropertySource 注解的底层实现机制 */ public class PropertySourceAnalysis { /** * 1. 注解作用 * * 将外部属性文件加载到Spring Environment中 * * 支持的协议: * - classpath: 从类路径加载 * - file: 从文件系统加载 * - http: 从网络加载 */ /** * 2. 加载流程 * * ConfigurationClassParser.processImports() * ↓ * 识别@PropertySource注解 * ↓ * PropertySourcesPlaceholderConfigurer 处理 * ↓ * 读取属性文件 * ↓ * 创建PropertySource * ↓ * 添加到Environment */ /** * 3. redis.properties 示例 * * redis.host=127.0.0.1 * redis.port=6379 * redis.password= * redis.database=0 * redis.timeout=3000 * * 使用方式: * @Value("${redis.host}") * private String redisHost; */ /** * 4. 属性查找优先级 * * Spring Boot属性源顺序(高到低): * 1. 命令行参数 * 2. ServletConfig init参数 * 3. ServletContext init参数 * 4. JNDI属性 * 5. JVM系统属性 * 6. JVM环境变量 * 7. @PropertySource注解 * 8. application.properties/yml * * 后加载的会覆盖先加载的同名属性 */ } ``` #### 2.3.2 扩展用法 ```java /** * @PropertySource 扩展用法 */ public class PropertySourceAdvanced { /** * 1. 加载多个文件 * @PropertySources({ * @PropertySource("classpath:redis.properties"), * @PropertySource("classpath:redis-dev.properties") * }) * * 2. 忽略找不到文件 * @PropertySource(value = "optional.properties", * ignoreResourceNotFound = true) * * 3. 指定编码 * @PropertySource(value = "redis.properties", * encoding = "UTF-8") * * 4. 自定义工厂 * @PropertySource(value = "redis.yml", * factory = YamlPropertySourceFactory.class) */ } ``` --- ### 2.4 @Autowired 注解 #### 2.4.1 底层原理 ```java /** * @Autowired 注解的底层实现机制 */ public class AutowiredAnalysis { /** * 1. 注入方式 * * a) 字段注入(当前使用) * @Autowired * private RedisTemplate redisTemplate; * * b) Setter注入 * @Autowired * public void setRedisTemplate(RedisTemplate template) { ... } * * c) 构造器注入(推荐) * private final RedisTemplate redisTemplate; * * @Autowired * public RedisUtil(RedisTemplate redisTemplate) { * this.redisTemplate = redisTemplate; * } */ /** * 2. 注入流程 * * ① 创建Bean实例 * ② AutowiredAnnotationBeanPostProcessor 处理 * ③ 扫描@Autowired注解 * ④ 解析依赖类型 * ⑤ 在BeanFactory中查找匹配Bean * ⑥ 反射设置字段值 * ⑦ 完成依赖注入 */ /** * 3. 反射注入实现 * * Field field = RedisUtil.class.getDeclaredField("redisTemplate"); * field.setAccessible(true); * field.set(redisUtilInstance, redisTemplateBean); */ /** * 4. 依赖查找策略 * * 按类型查找: * - RedisTemplate.class * - 找到匹配的Bean * - 如果有多个候选,按@Primary、@Priority排序 * * 按名称查找: * @Autowired * @Qualifier("redisTemplate") * private RedisTemplate redisTemplate; */ } ``` #### 2.4.2 三种注入方式对比 ```java /** * 三种注入方式对比 */ public class InjectionMethodComparison { /** * 字段注入: * - 优点:代码简洁 * - 缺点:无法设置final,不利于单元测试 * * Setter注入: * - 优点:可选依赖,可多次调用 * - 缺点:无法保证必需依赖 * * 构造器注入(推荐): * - 优点:保证不可变性,明确依赖关系 * - 缺点:代码稍长 */ } ``` #### 2.4.3 源码核心类 ```java /** * @Autowired 源码核心类 */ public class AutowiredSourceCode { /** * 核心处理类: * * 1. AutowiredAnnotationBeanPostProcessor * - 处理@Autowired、@Value、@Inject注解 * - 在属性填充阶段工作 * * 2. DefaultListableBeanFactory * - 提供Bean查找功能 * - resolveDependency()方法 * * 3. DependencyDescriptor * - 描述依赖信息 * - 包含类型、注解等信息 * * 执行时序: * createBeanInstance() * ↓ * populateBean() * ↓ * AutowiredAnnotationBeanPostProcessor.postProcessProperties() * ↓ * InjectionMetadata.inject() * ↓ * field.set() / method.invoke() */ } ``` --- ### 2.5 @Component 注解 #### 2.5.1 底层原理 ```java /** * @Component 注解的底层实现机制 */ public class ComponentAnalysis { /** * 1. 注解层次结构 * * @Component (元注解) * ├── @Service (服务层) * ├── @Repository (持久层) * ├── @Controller (控制层) * └── @RestController (REST控制器) * * 本质上都是 @Component,语义不同 */ /** * 2. 组件扫描流程 * * @SpringBootApplication * ↓ 包含 @ComponentScan * ↓ * ClassPathScanningCandidateComponentProvider * ↓ * 扫描指定包路径 * ↓ * 识别@Component注解 * ↓ * 创建BeanDefinition * ↓ * 注册到BeanDefinitionRegistry */ /** * 3. BeanDefinition生成 * * 扫描到 RedisUtil.class 后: * * BeanDefinition beanDef = new AnnotatedGenericBeanDefinition(RedisUtil.class); * beanDef.setBeanClass(RedisUtil.class); * beanDef.setScope("singleton"); * beanDef.setLazyInit(false); * beanDef.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE); * beanDef.setPrimary(false); * * registry.registerBeanDefinition("redisUtil", beanDef); * * Bean名称规则: * - 类名首字母小写:RedisUtil -> "redisUtil" * - 自定义:@Component("customName") */ } ``` #### 2.5.2 组件扫描深度分析 ```java /** * 组件扫描深度分析 */ public class ComponentScanDeepDive { /** * 扫描原理: * * 1. 获取类路径资源 * ClassPathScanningCandidateComponentProvider.findCandidateComponents() * * 2. 解析.class文件 * 通过ASM字节码分析(不加载类) * 读取类元数据和注解信息 * * 3. 应用过滤器 * includeFilters:包含的组件 * excludeFilters:排除的组件 * * 4. 生成BeanDefinition * AnnotatedGenericBeanDefinition * * 5. 注册到容器 * BeanDefinitionRegistry.registerBeanDefinition() */ /** * 过滤器类型: * * FilterType.ANNOTATION:按注解过滤 * FilterType.ASSIGNABLE_TYPE:按类型过滤 * FilterType.ASPECTJ:按AspectJ表达式过滤 * FilterType.REGEX:按正则表达式过滤 * FilterType.CUSTOM:自定义过滤器 */ } ``` --- ### 2.6 @RestController 注解 #### 2.6.1 底层原理 ```java /** * @RestController 注解的底层实现机制 */ public class RestControllerAnalysis { /** * 1. 注解组合 * * @RestController = @Controller + @ResponseBody * * @Controller:标记为Spring MVC控制器 * @ResponseBody:所有方法返回值直接作为响应体 */ /** * 2. 处理流程 * * ① HTTP请求到达 * ② DispatcherServlet 接收请求 * ③ HandlerMapping 查找处理器方法 * ④ 找到 getKey() 方法 * ⑤ 调用方法获取返回值 * ⑥ RequestMappingHandlerAdapter 处理 * ⑦ @ResponseBody 生效 * ⑧ MessageConverter 转换返回值 * ⑨ 序列化为JSON * ⑩ 返回HTTP响应 */ /** * 3. 与@Controller的区别 * * @Controller: * @RequestMapping("/hello") * public String hello() { * return "hello"; // 返回视图名称 * } * * @RestController: * @RequestMapping("/hello") * public String hello() { * return "hello"; // 返回"hello"字符串(不是视图) * } * * 等价于: * @Controller * public class Controller { * @ResponseBody * @RequestMapping("/hello") * public String hello() { ... } * } */ /** * 4. 消息转换 * * 返回值转换流程: * * 返回对象 → MessageConverter → JSON字符串 → HTTP响应 * * 支持的消息转换器: * - StringHttpMessageConverter * - ByteArrayHttpMessageConverter * - MappingJackson2HttpMessageConverter * - MappingJackson2XmlHttpMessageConverter * * 根据Accept和Content-Type自动选择 */ } ``` #### 2.6.2 请求处理完整流程 ```java /** * 请求处理完整流程 */ public class RequestHandlingFlow { /** * 完整请求处理链路: * * 1. 请求到达 → DispatcherServlet.doDispatch() * * 2. 处理器映射 → HandlerMapping.getHandler() * - 查找@RequestMapping匹配的方法 * - 返回HandlerExecutionChain * * 3. 处理器适配 → HandlerAdapter.handle() * - 调用getKey(key)方法 * - 获取返回值 * * 4. 消息转换 → HttpMessageConverter.write() * - 将对象转换为JSON * - 写入响应流 * * 5. 视图渲染 → (@RestController跳过此步) * * 6. 返回响应 → Response提交 */ /** * 拦截器链: * * HandlerExecutionChain: * - Object handler(处理器方法) * - List interceptors(拦截器) * * 执行顺序: * preHandle() → controller → postHandle() → afterCompletion() */ } ``` --- ### 2.7 @RequestMapping 注解 #### 2.7.1 底层原理 ```java /** * @RequestMapping 注解的底层实现机制 */ public class RequestMappingAnalysis { /** * 1. 注解属性 * * String[] value() default {}; // URL路径 * String[] path() default {}; // 同value * RequestMethod[] method() default {}; // HTTP方法 * String[] params() default {}; // 请求参数 * String[] headers() default {}; // 请求头 * String[] consumes() default {}; // 请求内容类型 * String[] produces() default {}; // 响应内容类型 * * 使用示例: * @RequestMapping( * value = "/users/{id}", * method = RequestMethod.GET, * params = "version=1.0", * headers = "X-Requested-With=XMLHttpRequest", * consumes = "application/json", * produces = "application/json" * ) */ /** * 2. 路径映射原理 * * Spring MVC维护一个映射表: * * Map urlMappings; * * "/getKey" → GetKeyController.getKey() * * 路径匹配策略: * - 精确匹配:/getKey * - 路径变量:/users/{id} * - 通配符:/users/* * - 正则:/users/{id:[0-9]+} */ /** * 3. @RequestMapping 派生注解 * * @GetMapping = @RequestMapping(method = GET) * @PostMapping = @RequestMapping(method = POST) * @PutMapping = @RequestMapping(method = PUT) * @DeleteMapping = @RequestMapping(method = DELETE) * @PatchMapping = @RequestMapping(method = PATCH) * * 使用示例: * @GetMapping("/getKey") // 等价于上面的写法 * public Object getKey(@RequestParam String key) { ... } */ /** * 4. 参数解析 * * @RequestParam String key * * 解析流程: * ① 从HttpServletRequest中获取参数 * ② request.getParameter("key") * ③ 类型转换(如果需要) * ④ 赋值给方法参数 * * 等价于: * String key = request.getParameter("key"); */ } ``` #### 2.7.2 路径匹配深度分析 ```java /** * 路径匹配深度分析 */ public class PathMatchingDeepDive { /** * 路径匹配算法: * * 1. Ant风格匹配 * ? 匹配单个字符 * * 匹配0或多个字符 * ** 匹配0或多级路径 * * 2. 示例: * /getKey → /getKey ✓ * /getKey* → /getKey/123 ✓ * /users/** → /users/123/profile ✓ * * 3. 路径变量 * /users/{id} → /users/123 * id = "123" * * 4. 正则路径变量 * /users/{id:[0-9]+} * /users/abc → 不匹配 * /users/123 → 匹配 */ } ``` --- ## Redis配置深度解析 ### 3.1 RedisTemplate 配置流程 #### 3.1.1 整体配置流程 ```java /** * RedisTemplate 配置详细分析 */ public class RedisTemplateConfigurationAnalysis { /** * 1. 整体配置流程图 * * ┌─────────────────────────────────────────────────────────────┐ * │ Spring Boot 启动 │ * ├─────────────────────────────────────────────────────────────┤ * │ │ * │ ┌──────────────────┐ │ * │ │ @Configuration │ │ * │ │ 扫描 │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ 解析 @Bean │ │ * │ │ redisTemplate() │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ 查找 │ │ * │ │ RedisConnectionFactory │ * │ │ (Spring Boot自动配置) │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ 创建 │ │ * │ │ RedisTemplate │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ 配置序列化器 │ │ * │ │ (Key/Value) │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ 注册到容器 │ │ * │ └──────────────────┘ │ * │ │ * └─────────────────────────────────────────────────────────────┘ */ } ``` #### 3.1.2 RedisConnectionFactory 的来源 ```java /** * RedisConnectionFactory 的来源 */ public class RedisConnectionFactorySource { /** * Spring Boot自动配置流程: * * RedisAutoConfiguration * ↓ * 创建 RedisConnectionFactory * ↓ * 根据配置选择实现: * - LettuceConnectionFactory(默认) * - JedisConnectionFactory * ↓ * 配置连接参数: * - host、port、password、database * ↓ * 注册为Bean */ /** * 自动配置条件: * * @ConditionalOnClass(RedisOperations.class) * @ConditionalOnMissingBean(name = "redisTemplate") * @EnableConfigurationProperties(RedisProperties.class) * * 条件满足时: * 1. 加载RedisProperties配置 * 2. 创建RedisConnectionFactory * 3. 创建RedisTemplate * 4. 创建StringRedisTemplate */ } ``` #### 3.1.3 为什么需要配置RedisTemplate? ```java /** * 为什么需要配置RedisTemplate? */ public class WhyConfigureRedisTemplate { /** * Spring Boot默认的RedisTemplate配置: * - Key序列化器:StringRedisSerializer * - Value序列化器:JdkSerializationRedisSerializer * * 问题: * - JdkSerializationRedisSerializer要求对象实现Serializable * - 序列化结果不可读 * - 跨语言兼容性差 * * 解决方案: * - 使用JSON序列化 * - Key使用String序列化 * - Value使用JSON序列化 */ } ``` #### 3.1.4 配置代码逐行解析 ```java /** * 配置代码逐行解析 */ public class RedisConfigCodeAnalysis { /** * 步骤1:创建RedisTemplate实例 */ /* RedisTemplate redisTemplate = new RedisTemplate(); 底层实现: - new RedisTemplate() - 初始化内部属性 - 创建默认的序列化器(会被覆盖) */ /** * 步骤2:设置连接工厂 */ /* redisTemplate.setConnectionFactory(factory); 底层实现: - 保存RedisConnectionFactory引用 - 用于创建Redis连接 - 实际使用时会调用factory.getConnection() */ /** * 步骤3:配置Key序列化器 */ /* StringRedisSerializer keySerializer = new StringRedisSerializer(); redisTemplate.setKeySerializer(keySerializer); redisTemplate.setHashKeySerializer(keySerializer); 为什么Key使用String序列化? - Redis的Key必须是字符串 - 便于阅读和调试 - 便于使用Redis命令行工具查看 底层实现: StringRedisSerializer.serialize(Object obj): return obj.toString().getBytes(StandardCharsets.UTF_8); */ /** * 步骤4:配置Value序列化器 */ /* ObjectMapper objectMapper = new ObjectMapper(); GenericJacksonJsonRedisSerializer valueSerializer = new GenericJacksonJsonRedisSerializer(objectMapper); redisTemplate.setValueSerializer(valueSerializer); redisTemplate.setHashValueSerializer(valueSerializer); 为什么Value使用JSON序列化? - 对象不需要实现Serializable - 序列化结果可读 - 跨语言兼容性好 - 支持复杂对象 底层实现: GenericJacksonJsonRedisSerializer.serialize(Object obj): return objectMapper.writeValueAsBytes(obj); ObjectMapper作用: - Jackson的核心类 - 负责对象和JSON的转换 - 支持复杂的对象映射 */ } ``` #### 3.1.5 序列化器类型对比 ```java /** * 序列化器类型对比 */ public class RedisSerializerComparison { /* 序列化器对比表: ┌────────────────────────────────────────────────────────────────┐ │ 序列化器 │ 优点 │ 缺点 │ ├────────────────────────────────────────────────────────────────┤ │ StringRedisSerializer │ 可读、兼容性好 │ 只能序列化字符串│ ├────────────────────────────────────────────────────────────────┤ │ JdkSerializationRedisSerializer│ 无需额外依赖 │ 不可读、性能差 │ ├────────────────────────────────────────────────────────────────┤ │ JacksonJsonRedisSerializer │ 可读、跨语言 │ 需要Jackson依赖│ ├────────────────────────────────────────────────────────────────┤ │ GenericJacksonJsonRedisSerializer│ 支持泛型、类型信息│ 稍慢 │ └────────────────────────────────────────────────────────────────┘ */ } ``` --- ### 3.2 Redis序列化深度分析 #### 3.2.1 序列化流程 ```java /** * Redis序列化深度分析 */ public class RedisSerializationDeepDive { /** * 序列化流程: * * 调用 redisTemplate.opsForValue().set("user:1", user) * ↓ * 获取Value序列化器:GenericJacksonJsonRedisSerializer * ↓ * 序列化对象:objectMapper.writeValueAsBytes(user) * ↓ * 转换为JSON字符串:{"id":1,"name":"张三"} * ↓ * 转换为字节数组 * ↓ * 发送到Redis * * Redis中的存储: * Key: user:1 * Value: {"id":1,"name":"张三"} */ /** * 反序列化流程: * * 调用 redisTemplate.opsForValue().get("user:1") * ↓ * 从Redis获取字节数组 * ↓ * 使用Value序列化器反序列化 * ↓ * objectMapper.readValue(bytes, Object.class) * ↓ * 转换为User对象 * ↓ * 返回User对象 */ /** * GenericJackson vs Jackson * * JacksonJsonRedisSerializer: * - 简单的JSON序列化 * - 不包含类型信息 * - 反序列化时需要指定类型 * * GenericJacksonJsonRedisSerializer: * - 包含类型信息 * - 支持泛型 * - 自动类型推断 * - 稍微慢一点 * * 示例: * Jackson: {"id":1,"name":"张三"} * Generic: {"@class":"com.kc.User","id":1,"name":"张三"} */ } ``` #### 3.2.2 ObjectMapper 配置 ```java /** * ObjectMapper 配置 */ public class ObjectMapperConfiguration { /** * ObjectMapper 常用配置: * * ObjectMapper mapper = new ObjectMapper(); * * // 忽略未知属性 * mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); * * // 包含null值 * mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); * * // 日期格式化 * mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); * * // 美化输出 * mapper.configure(SerializationFeature.INDENT_OUTPUT, true); * * // 使用驼峰命名 * mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); */ } ``` --- ## 依赖注入流程深度解析 ### 4.1 RedisUtil 依赖注入 #### 4.1.1 完整注入流程 ```java /** * RedisUtil 依赖注入详细分析 */ public class RedisUtilDependencyInjection { /** * 1. 完整注入流程 * * ┌─────────────────────────────────────────────────────────────┐ * │ Bean创建流程 │ * ├─────────────────────────────────────────────────────────────┤ * │ │ * │ ┌──────────────────┐ │ * │ │ ① 扫描发现 │ │ * │ │ RedisUtil │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ ② 创建实例 │ │ * │ │ new RedisUtil() │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ ③ 属性注入 │ │ * │ │ @Autowired │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ ④ 查找依赖 │ │ * │ │ RedisTemplate │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ ⑤ 反射设置 │ │ * │ │ field.set() │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ ⑥ 初始化回调 │ │ * │ │ @PostConstruct │ │ * │ └────────┬─────────┘ │ * │ │ │ * │ ▼ │ * │ ┌──────────────────┐ │ * │ │ ⑦ Bean就绪 │ │ * │ └──────────────────┘ │ * │ │ * └─────────────────────────────────────────────────────────────┘ */ } ``` #### 4.1.2 反射注入实现细节 ```java /** * 反射注入实现细节 */ public class ReflectionInjectionDetails { /** * 源码实现(简化版): * * // AutowiredAnnotationBeanPostProcessor * public void inject(Object bean, String beanName) { * // 扫描@Autowired注解的字段 * Field[] fields = bean.getClass().getDeclaredFields(); * for (Field field : fields) { * if (field.isAnnotationPresent(Autowired.class)) { * // 获取字段类型 * Class type = field.getType(); * * // 从容器中查找Bean * Object dependency = beanFactory.getBean(type); * * // 反射设置字段值 * field.setAccessible(true); * field.set(bean, dependency); * } * } * } */ } ``` #### 4.1.3 依赖解析策略 ```java /** * 依赖解析策略 */ public class DependencyResolutionStrategy { /** * 查找RedisTemplate的步骤: * * ① 获取字段类型:RedisTemplate.class * ② 在BeanFactory中查找: * - 按类型查找:getBean(RedisTemplate.class) * - 找到唯一匹配的Bean * ③ 如果有多个候选: * - 使用@Primary标记的 * - 使用@Priority优先级高的 * - 抛出NoUniqueBeanDefinitionException * ④ 如果没有找到: * - 尝试按名称查找 * - 抛出NoSuchBeanDefinitionException */ } ``` --- ### 4.2 Spring Bean生命周期 #### 4.2.1 完整生命周期 ```java /** * Spring Bean 生命周期完整流程 */ public class SpringBeanLifecycle { /** * 完整生命周期: * * 1. 实例化 * - 创建Bean实例 * - 构造器调用 * * 2. 属性填充 * - @Autowired注入 * - @Value注入 * * 3. 初始化 * - BeanNameAware * - BeanFactoryAware * - ApplicationContextAware * - @PostConstruct * - InitializingBean.afterPropertiesSet() * - 自定义init-method * * 4. 使用 * - Bean处于可用状态 * - 提供服务 * * 5. 销毁 * - @PreDestroy * - DisposableBean.destroy() * - 自定义destroy-method */ } ``` #### 4.2.2 生命周期回调 ```java /** * 生命周期回调示例 */ public class LifecycleCallbackExample { /** * 示例代码: * * @Component * public class RedisUtil implements InitializingBean, DisposableBean { * * @Autowired * private RedisTemplate redisTemplate; * * // 构造器 * public RedisUtil() { * System.out.println("1. 构造器调用"); * } * * // 属性注入完成后 * @PostConstruct * public void postConstruct() { * System.out.println("2. @PostConstruct"); * } * * // InitializingBean回调 * @Override * public void afterPropertiesSet() { * System.out.println("3. afterPropertiesSet"); * } * * // 销毁前 * @PreDestroy * public void preDestroy() { * System.out.println("4. @PreDestroy"); * } * * // DisposableBean回调 * @Override * public void destroy() { * System.out.println("5. destroy"); * } * } */ } ``` --- ## 请求处理完整流程 ### 5.1 HTTP请求到响应全链路 #### 5.1.1 完整请求链路图 ```java /** * HTTP请求完整处理流程 */ public class HttpRequestProcessingFlow { /** * 1. 完整请求链路图 * * ┌─────────────────────────────────────────────────────────────┐ * │ HTTP请求处理流程 │ * ├─────────────────────────────────────────────────────────────┤ * │ │ * │ 客户端浏览器 │ * │ │ * │ HTTP GET /getKey?key=test │ * ▼ │ * │ Tomcat服务器 │ * │ │ * │ 转发到DispatcherServlet │ * ▼ │ * │ DispatcherServlet │ * │ │ * ├─→ doDispatch() │ * │ │ * ├─→ HandlerMapping.getHandler() │ * │ 找到GetKeyController.getKey()方法 │ * │ │ * ├─→ HandlerInterceptor.preHandle() │ * │ 执行拦截器前置处理 │ * │ │ * ├─→ HandlerAdapter.handle() │ * │ 调用getKey(key)方法 │ * │ │ │ * │ ├─→ 参数解析 │ * │ │ @RequestParam String key │ * │ │ 从HTTP请求中提取参数 │ * │ │ │ * │ ├─→ 依赖注入 │ * │ │ redisUtil.get(key) │ * │ │ │ │ * │ │ └─→ RedisTemplate.opsForValue().get(key) │ * │ │ │ │ * │ │ └─→ Redis操作 │ * │ │ 发送Redis命令 │ * │ │ 等待响应 │ * │ │ 反序列化结果 │ * │ │ │ * │ └─→ 返回结果 │ * │ Object value │ * │ │ * ├─→ HandlerInterceptor.postHandle() │ * │ 执行拦截器后置处理 │ * │ │ * ├─→ @ResponseBody处理 │ * │ MessageConverter.write() │ * │ 将对象转换为JSON │ * │ │ * └─→ 返回HTTP响应 │ * 200 OK │ * Content-Type: application/json │ * Body: {"name":"张三"} │ * │ * └─────────────────────────────────────────────────────────────┘ */ } ``` #### 5.1.2 参数解析详细流程 ```java /** * 参数解析详细流程 */ public class ParameterParsingFlow { /** * @RequestParam String key * * 解析步骤: * ① 创建RequestParamMethodArgumentResolver * ② 从HttpServletRequest获取参数 * ③ String key = request.getParameter("key"); * ④ 类型转换(如果需要) * ⑤ 参数验证(@Valid) * ⑥ 返回方法参数 */ } ``` #### 5.1.3 消息转换详细流程 ```java /** * 消息转换详细流程 */ public class MessageConversionFlow { /** * 返回值:Object value * * 转换步骤: * ① 确定返回值类型:Object.class * ② 选择MessageConverter: * - MappingJackson2HttpMessageConverter * ③ 序列化对象: * - objectMapper.writeValueAsString(value) * - 转换为JSON字符串 * ④ 设置响应头: * - Content-Type: application/json;charset=UTF-8 * ⑤ 写入响应流 */ } ``` #### 5.1.4 Redis操作详细流程 ```java /** * Redis操作详细流程 */ public class RedisOperationFlow { /** * redisTemplate.opsForValue().get(key) * * 执行步骤: * ① 获取连接: * - RedisConnection connection = factory.getConnection() * ② 序列化Key: * - byte[] keyBytes = keySerializer.serialize(key) * ③ 发送Redis命令: * - connection.get(keyBytes) * ④ 接收响应: * - byte[] valueBytes = connection.get(keyBytes) * ⑤ 反序列化Value: * - Object value = valueSerializer.deserialize(valueBytes) * ⑥ 释放连接 * ⑦ 返回结果 */ } ``` --- ### 5.2 Spring MVC核心组件 #### 5.2.1 核心组件职责 ```java /** * Spring MVC核心组件 */ public class SpringMVCCoreComponents { /** * 核心组件职责: * * 1. DispatcherServlet(前端控制器) * - 统一请求入口 * - 协调各个组件工作 * * 2. HandlerMapping(处理器映射) * - 根据URL查找处理器方法 * - 维护URL到Handler的映射表 * * 3. HandlerAdapter(处理器适配器) * - 调用处理器方法 * - 参数解析、返回值处理 * * 4. HandlerInterceptor(拦截器) * - 前置/后置处理 * - 横切关注点 * * 5. HttpMessageConverter(消息转换器) * - 请求/响应的序列化 * - 支持多种格式 * * 6. ViewResolver(视图解析器) * - 解析视图名称 * - @RestController不使用 * * 7. ExceptionResolver(异常解析器) * - 处理异常 * - 返回错误响应 */ } ``` #### 5.2.2 组件工作流程 ```java /** * 组件工作流程 */ public class ComponentWorkflow { /** * 组件协作流程: * * 1. 请求到达 → DispatcherServlet * 2. 处理器映射 → HandlerMapping * 3. 处理器适配 → HandlerAdapter * 4. 拦截器处理 → HandlerInterceptor * 5. 消息转换 → HttpMessageConverter * 6. 视图渲染 → ViewResolver(可选) * 7. 响应返回 → 客户端 */ } ``` --- ## 框架底层工作总结 ### 6.1 Spring Boot 启动流程 #### 6.1.1 启动流程详解 ```java /** * Spring Boot 完整启动流程 */ public class SpringBootStartupFlow { /** * 启动流程: * * ① SpringApplication.run() * ↓ * ② 创建SpringApplication * ↓ * ③ 准备Environment * ↓ * ④ 创建ApplicationContext * ↓ * ⑤ 刷新ApplicationContext * - 扫描@Component * - 处理@Configuration * - 创建@Bean实例 * - 依赖注入 * ↓ * ⑥ 启动Web服务器 * ↓ * ⑦ 应用启动完成 */ } ``` #### 6.1.2 自动配置原理 ```java /** * 自动配置原理 */ public class AutoConfigurationPrinciple { /** * 自动配置流程: * * @SpringBootApplication * ↓ 包含 @EnableAutoConfiguration * ↓ * 读取META-INF/spring.factories * ↓ * 加载自动配置类: * - RedisAutoConfiguration * - DataSourceAutoConfiguration * - WebMvcAutoConfiguration * ↓ * 根据条件决定是否配置: * @ConditionalOnClass * @ConditionalOnMissingBean * @ConditionalOnProperty */ } ``` --- ### 6.2 Spring Bean生命周期 #### 6.2.1 生命周期详解 ```java /** * Spring Bean 生命周期完整流程 */ public class BeanLifecycleComplete { /** * Bean生命周期阶段: * * 阶段1:实例化 * - 调用构造器 * - 创建Bean实例 * * 阶段2:属性填充 * - @Autowired注入 * - @Value注入 * - @Resource注入 * * 阶段3:初始化 * - BeanNameAware.setBeanName() * - BeanFactoryAware.setBeanFactory() * - ApplicationContextAware.setApplicationContext() * - @PostConstruct * - InitializingBean.afterPropertiesSet() * - 自定义init-method * * 阶段4:使用 * - Bean处于可用状态 * - 提供服务 * * 阶段5:销毁 * - @PreDestroy * - DisposableBean.destroy() * - 自定义destroy-method */ } ``` #### 6.2.2 生命周期图 ```java /** * 生命周期图 */ public class BeanLifecycleDiagram { /** * 完整生命周期图: * * ┌─────────────────────────────────────────────────────────────┐ * │ Bean 生命周期 │ * ├─────────────────────────────────────────────────────────────┤ * │ │ * │ 实例化 → 属性填充 → 初始化 → 使用 → 销毁 │ * │ │ * │ [构造器] [@Autowired] [@PostConstruct] [提供服务] [@PreDestroy] │ * │ │ * └─────────────────────────────────────────────────────────────┘ */ } ``` --- ## 最佳实践建议 ### 7.1 代码改进建议 #### 7.1.1 使用构造器注入 ```java /** * 改进建议:使用构造器注入 */ public class ConstructorInjectionExample { /** * 原代码: * @Autowired * private RedisTemplate redisTemplate; * * 改进后: * private final RedisTemplate redisTemplate; * * @Autowired * public RedisUtil(RedisTemplate redisTemplate) { * this.redisTemplate = redisTemplate; * } */ } ``` #### 7.1.2 使用@GetMapping ```java /** * 改进建议:使用@GetMapping */ public class GetMappingExample { /** * 原代码: * @RequestMapping("/getKey") * * 改进后: * @GetMapping("/getKey") * * 优点: * - 更明确表达HTTP方法 * - 代码更易读 * - IDE支持更好 */ } ``` #### 7.1.3 添加参数验证 ```java /** * 改进建议:添加参数验证 */ public class ParameterValidationExample { /** * 原代码: * public Object getKey(@RequestParam String key) * * 改进后: * public Object getKey(@RequestParam @NotBlank String key) * * 优点: * - 防止空参数 * - 提高代码健壮性 * - 自动参数校验 */ } ``` #### 7.1.4 添加异常处理 ```java /** * 改进建议:添加异常处理 */ public class ExceptionHandlingExample { /** * 添加全局异常处理器: * * @RestControllerAdvice * public class GlobalExceptionHandler { * * @ExceptionHandler(Exception.class) * public ResponseEntity handleException(Exception e) { * log.error("请求处理异常", e); * return ResponseEntity.status(500) * .body("服务器内部错误: " + e.getMessage()); * } * * @ExceptionHandler(RedisConnectionException.class) * public ResponseEntity handleRedisException(RedisConnectionException e) { * log.error("Redis连接异常", e); * return ResponseEntity.status(503) * .body("Redis服务不可用"); * } * } */ } ``` #### 7.1.5 添加日志 ```java /** * 改进建议:添加日志 */ public class LoggingExample { /** * 使用日志记录: * * @Slf4j * @RestController * public class GetKeyController { * * @Autowired * private RedisUtil redisUtil; * * @GetMapping("/getKey") * public Object getKey(@RequestParam String key) { * log.info("收到获取Redis key请求: {}", key); * * Object value = redisUtil.get(key); * * if (value != null) { * log.info("成功获取Redis key: {}", key); * return value; * } else { * log.warn("Redis key不存在: {}", key); * return "miss key !!!"; * } * } * } */ } ``` --- ### 7.2 完整改进代码 #### 7.2.1 改进后的RedisUtil ```java /** * 改进后的RedisUtil */ @Component @Slf4j public class RedisUtil { private final RedisTemplate redisTemplate; // 使用构造器注入 public RedisUtil(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; log.info("RedisUtil初始化完成"); } /** * 获取缓存 * @param key 缓存键 * @return 缓存值 */ public Object get(String key) { try { if (StringUtils.hasText(key) && redisTemplate.hasKey(key)) { return redisTemplate.opsForValue().get(key); } return null; } catch (Exception e) { log.error("获取Redis缓存异常,key: {}", key, e); throw new RuntimeException("获取缓存失败", e); } } /** * 设置缓存 * @param key 缓存键 * @param value 缓存值 */ public void set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); } catch (Exception e) { log.error("设置Redis缓存异常,key: {}", key, e); throw new RuntimeException("设置缓存失败", e); } } /** * 设置缓存并指定过期时间 * @param key 缓存键 * @param value 缓存值 * @param timeout 过期时间 * @param unit 时间单位 */ public void set(String key, Object value, long timeout, TimeUnit unit) { try { redisTemplate.opsForValue().set(key, value, timeout, unit); } catch (Exception e) { log.error("设置Redis缓存异常,key: {}, timeout: {}", key, timeout, e); throw new RuntimeException("设置缓存失败", e); } } /** * 删除缓存 * @param key 缓存键 */ public void delete(String key) { try { redisTemplate.delete(key); } catch (Exception e) { log.error("删除Redis缓存异常,key: {}", key, e); throw new RuntimeException("删除缓存失败", e); } } } ``` #### 7.2.2 改进后的Controller ```java /** * 改进后的Controller */ @RestController @Slf4j @RequestMapping("/redis") public class RedisController { private final RedisUtil redisUtil; public RedisController(RedisUtil redisUtil) { this.redisUtil = redisUtil; } /** * 获取Redis值 */ @GetMapping("/get") public ResponseEntity getKey(@RequestParam @NotBlank String key) { log.info("收到获取Redis请求,key: {}", key); Object value = redisUtil.get(key); if (value != null) { log.info("成功获取Redis值,key: {}", key); return ResponseEntity.ok(value); } else { log.warn("Redis key不存在,key: {}", key); return ResponseEntity.status(HttpStatus.NOT_FOUND) .body("miss key !!!"); } } /** * 设置Redis值 */ @PostMapping("/set") public ResponseEntity setKey(@RequestParam @NotBlank String key, @RequestBody Object value) { log.info("收到设置Redis请求,key: {}", key); redisUtil.set(key, value); log.info("成功设置Redis值,key: {}", key); return ResponseEntity.ok("success"); } } ``` --- ## 总结 ### 8.1 核心知识点总结 通过本文的深度解析,我们掌握了以下核心知识点: #### 8.1.1 注解工作原理 1. **@Configuration** - CGLIB代理保证单例 - @Bean方法返回同一个实例 - 支持配置类间依赖 2. **@Bean** - 方法工厂创建Bean - 参数自动依赖注入 - 支持自定义初始化/销毁 3. **@Autowired** - 反射依赖注入 - 三种注入方式对比 - 依赖解析策略 4. **@Component** - 组件扫描注册 - BeanDefinition生成 - 过滤器机制 5. **@RestController** - @Controller + @ResponseBody - 返回JSON响应 - 消息转换 #### 8.1.2 框架底层机制 1. **Spring IOC** - 依赖注入 - Bean管理 - 生命周期 2. **Spring MVC** - 请求映射 - 参数解析 - 响应转换 3. **Spring Data Redis** - Redis操作封装 - 序列化机制 - 连接管理 #### 8.1.3 序列化机制 1. **StringRedisSerializer** - Key序列化 - UTF-8编码 - 可读性好 2. **GenericJacksonJsonRedisSerializer** - Value序列化 - 包含类型信息 - 支持泛型 3. **ObjectMapper** - JSON转换核心 - 可配置性强 - 性能优秀 #### 8.1.4 请求处理流程 1. **DispatcherServlet** - 统一请求入口 - 协调各组件 2. **HandlerMapping** - URL到Handler映射 - 路径匹配算法 3. **HandlerAdapter** - 方法调用 - 参数解析 4. **MessageConverter** - 请求/响应转换 - 支持多种格式 --- ### 8.2 关键要点回顾 通过这篇深度解析,你应该对Spring Boot + Redis配置的底层原理有了全面的理解。关键要点: 1. **注解是元数据**:Spring通过注解扫描、解析、处理来实现各种功能 2. **反射是核心**:大量的反射操作实现依赖注入和方法调用 3. **代理是关键**:CGLIB代理保证@Bean方法的单例性 4. **序列化是桥梁**:Java对象和Redis数据之间的转换 5. **自动配置是魔法**:Spring Boot通过条件注解实现智能配置 6. **生命周期是基础**:理解Bean生命周期有助于掌握Spring工作原理 7. **依赖注入是灵魂**:Spring IOC的核心实现机制 --- ### 8.3 学习建议 1. **深入阅读源码** - 阅读Spring核心源码 - 理解设计模式应用 - 学习最佳实践 2. **动手实践** - 编写自定义注解 - 实现简单IOC容器 - 开发拦截器 3. **性能优化** - 关注序列化性能 - 优化连接池配置 - 监控Redis性能 4. **安全考虑** - 配置Redis密码 - 使用SSL连接 - 验证输入参数 --- ## 参考资料 - [Spring Framework官方文档](https://docs.spring.io/spring-framework/) - [Spring Boot官方文档](https://docs.spring.io/spring-boot/) - [Spring Data Redis文档](https://docs.spring.io/spring-data/redis/) - [Jackson官方文档](https://github.com/FasterXML/jackson) --- 希望这篇深度解析能够帮助你更好地理解Spring Boot + Redis的配置原理和底层实现!如果你有任何问题或建议,欢迎留言讨论。
评论 0

发表评论 取消回复

Shift+Enter 换行  ·  Enter 发送
还没有评论,来发表第一条吧