Spring boot 特性和自写Reids组件 从MVC到bootSpring Framework AOP、IOC/DISpring 万能胶如何对配置进行轻量化思考MVC项目如何完成一个代码编写创建一个项目结构maven/gradlespring的依赖spring mvc 、servlet api的依赖web.xml DispatcherServlet启动一个Spring mVC的配置Dispatcher-servlet.xml创建一个Controller 发布一个http请求发布到jsp/servlet容器如果要引入mybatis还需要各种各样的配置Spring的产生在主容器引导 spring 容器内配置 Web 容器服务什么是Boot只要依赖的spring-boot-starter-web的jar就会自动内置一个tomcat容器(替换)项目结构默认提供了配置文件application.propertiesstarter启动依赖 - 如果是一个webstarter 默认认为你是去构建一个spring mvc的应用.EnableAutoConfiguration 自动装配 ?Starter 启动依赖 依赖于自动装配的技术Actuator 监控 , 提供了一些endpoint http、jmx形式去进行访问 health信息。 metrics 信息、 。。。Spring Boot CLI命令行操作的功能 groovy脚本 客户端, groovy微服务和BOOT那为什么Spring Cloud会采用Spring Boot来作为基础框架呢原因很简单1. Spring Cloud它是关注服务治理领域的解决方案而服务治理是依托于服务架构之上所以它仍然需要一个承载框架2. Spring Boot 可以简单认为它是一套快速配置Spring应用的脚手架它可以快速开发单个微服务所以spring cloud的版本和spring boot版本的兼容性有很大关联Boot的发展进程自动装配发展基于注解发展舍弃xml繁琐Spring 注解驱动发展历史1.0在SpringFramework1.x时代其中在1.2.0是这个时代的分水岭当时Java5刚刚发布业界正兴起了使用Annotation的技术风Spring Framework自然也提供了支持比如当时已经支持了Transactional等注解但是这个时候XML配置方式还是唯一选择。bean name class/Spring 2.x阶段新增注解Required检查属性是否完成注入Repository标记数据访问层DAOAspectAOP 切面注解XML 能力大幅增强支持可扩展 XML 命名空间第三方框架如 Dubbo可以通过扩展 Spring XML 标签无缝集成XML 依然是核心配置方式Spring 2.5 版本2.x 时代的分水岭1. 新增核心注解Autowired依赖注入Qualifier依赖查找 / 指定注入 Bean 名称Component通用组件标记Service业务逻辑层ServiceControllerWeb 控制层RequestMappingSpringMVC 请求映射关键依然是XML 配置驱动虽然有了大量注解但必须依靠 XML 才能生效!-- 开启注解处理器 → 让 Autowired 等注解生效 -- context:annotation-config/ !-- 扫描包下的注解类自动注册为Bean -- context:component-scan base-packagecom.example/context:annotation-config/注册注解处理器使注解生效context:component-scan/扫描包路径把Component/Service/Controller类自动注册成 Spring Bean替代了一部分手写的3.0使用AnnotationConfigApplicationContext加载去除了xml的方式纯注解 配置类 彻底抛弃 XMLConfiguration 去xml化核心目的是把bean对象如何更加便捷的方式去加载到Spring IOC容器中Component-Scan - Service Repository ControllerImportEnable模块驱动 启动自动配置Spring3.x版本中集成Redis或者mybatis创建配置类替代 XML 文件用 Bean 声明第三方组件的 Bean替代 XML 里的 bean 标签用 EnableXxx 启动模块自动装配相关组件底层也是注册处理器 / BeanPostProcessor自动装配思想ScheduledAnnotationBeanPostProcessor对应的是EnableScheduling注解的底层实现Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration { Bean(name TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) Role(BeanDefinition.ROLE_INFRASTRUCTURE) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); } }EnableScheduling注解会导入这个SchedulingConfiguration配置类自动注册ScheduledAnnotationBeanPostProcessor。这个处理器的作用就是扫描并处理所有Scheduled注解让定时任务生效。这也是所有EnableXxx注解的通用逻辑通过导入配置类自动注册相关的处理器 / Bean完成模块的初始化和装配。先注册后置处理器 → 再统一扫描、解析、生效注解EnableSchedulingImport(SchedulingConfiguration.class)作用让 Spring 提前加载这个配置类。Bean( name {org.springframework.context.annotation.internalScheduledAnnotationProcessor} ) Role(2) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); }前置核心把 “注解处理器” 提前放入 Spring 容器。ScheduledAnnotationBeanPostProcessor是一个BeanPostProcessor。它的工作时机Bean 初始化之后 → 后置处理阶段它干两件事扫描所有 Bean 上的 Scheduled 注解把这些方法注册成定时任务这就是先注册处理器前置 → 后处理注解后置一个注解自动注册全套组件 → 自动装配雏形你不需要知道谁在解析 Scheduled谁在注册任务任务执行器是谁只要开注解就能用 → 这就是自动装配3. 模块化装配EnableXXX 启动一个模块EnableScheduling → 开启定时任务EnableAsync → 开启异步EnableTransactionManagement → 开启事务EnableCaching → 开启缓存模式完全统一一个注解启动一套功能 自动装配的标准模型ScheduledAnnotationBeanPostProcessor 是 Spring 定时任务的核心中枢它是一个 Bean 后置处理器在 Bean 初始化之后扫描 Scheduled 注解解析任务规则注册并管理所有定时任务在容器初始化完成后统一启动。它通过后置处理 注解驱动 自动注册实现了完全无配置、开箱即用的定时任务能力是 Spring 自动装配思想最早期、最标准的实践模型。EnableScheduling→ 注册ScheduledAnnotationBeanPostProcessor→ 后置处理扫描Scheduled→ 解析、注册任务→ 容器启动 →任务自动执行4.0Spring 4.x Conditional条件装配Conditional是 Spring 4.0 引入的条件开关注解核心是在 Bean 注册前做条件判断满足才注册、不满足直接跳过它把 Spring 3.x 的 “注解驱动” 推进到按需驱动是 Spring Boot 自动配置的底层基石。// 自定义条件Linux系统 public class LinuxCondition implements Condition { Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return context.getEnvironment().getProperty(os.name).toLowerCase().contains(linux); } } // 配置类仅Linux环境才注册LinuxService Configuration Conditional(LinuxCondition.class) public class AppConfig { Bean public LinuxService linuxService() { return new LinuxService(); } }5.0Indexed —— 给组件扫描做 “索引”大幅提速Indexed 是 Spring 5.0 推出的「编译时组件索引」用来解决 Spring 项目变大后启动时 component-scan 扫描太慢的问题。它的核心思想不再启动时遍历所有 class 文件 → 编译时就生成索引 → 启动直接读索引 → 极快加载 Bean你写代码java运行Service public class UserService {}编译阶段还没运行Indexed扫描到这个类有组件注解自动写入文件META-INF/spring/components.idx内容plaintextcom.xxx.UserServiceorg.springframework.stereotype.Service项目启动Spring 不再全盘扫描 class直接读取这个索引文件瞬间就把 UserService 注册进 IOC 容器原理探究如图我们的Redis是零配置装载的按照思路。要么我们写BEan要么框架写BEan已知是框架写Bean那么需要注册哪些Bean框架怎么知道呢META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports由依赖来往里写入在spring-boot-autoconfigure-2.4.3.jar 写入又或者boot扫描写入加入// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.boot.autoconfigure.data.redis; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; Configuration( proxyBeanMethods false ) ConditionalOnClass({RedisOperations.class}) EnableConfigurationProperties({RedisProperties.class}) Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) public class RedisAutoConfiguration { public RedisAutoConfiguration() { } Bean ConditionalOnMissingBean( name {redisTemplate} ) ConditionalOnSingleCandidate(RedisConnectionFactory.class) public RedisTemplateObject, Object redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplateObject, Object template new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } Bean ConditionalOnMissingBean ConditionalOnSingleCandidate(RedisConnectionFactory.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }Import页导入了需要的SpringBootApplication(scanBasePackages com.rabbiter)EnableAutoConfigurationImport({AutoConfigurationImportSelector.class})AutoConfigurationImportSelector这段代码只干一件事去 spring.factories 里把所有 EnableAutoConfiguration 的类读出来把 RedisAutoConfiguration 从 spring.factories 里读出来交给 Spring 去注册 Beanprotected ListString getCandidateConfigurations(...) { // 1. 去读 spring.factories 文件 ListString configurations SpringFactoriesLoader.loadFactoryNames( this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader() ); // 2. 如果没读到直接报错找不到自动配置 Assert.notEmpty(configurations, No auto configuration classes found in META-INF/spring.factories...); // 3. 返回所有读到的配置类包括 Redis return configurations; }去所有 jar 包里读 META-INF/spring.factories 文件把所有自动配置类的名字全部读取出来你启动项目执行这个方法读取 spring.factories拿到 RedisAutoConfigurationSpring 自动注册RedisTemplate你直接Autowired