从MVC到boot
Spring Framework AOP、IOC/DI
Spring 万能胶
如何对配置进行轻量化
思考,MVC项目如何完成一个代码编写
创建一个项目结构(maven/gradle)
spring的依赖,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.properties
starter启动依赖 - 如果是一个webstarter ,默认认为你是去构建一个spring mvc的应用.
EnableAutoConfiguration 自动装配 ?
Starter 启动依赖 依赖于自动装配的技术
Actuator 监控 , 提供了一些endpoint ,http、jmx形式去进行访问, health信息。 metrics 信
息、 。。。
Spring Boot CLI(命令行操作的功能, groovy脚本) 客户端, groovy
微服务和BOOT
那为什么Spring Cloud会采用Spring Boot来作为基础框架呢?原因很简单
- Spring Cloud它是关注服务治理领域的解决方案,而服务治理是依托于服务架构之上,所以它仍然
需要一个承载框架
- 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:标记数据访问层(DAO)@Aspect:AOP 切面注解
-
XML 能力大幅增强
- 支持可扩展 XML 命名空间
- 第三方框架(如 Dubbo)可以通过扩展 Spring XML 标签无缝集成
- XML 依然是核心配置方式
Spring 2.5 版本(2.x 时代的分水岭)
- 新增核心注解
@Autowired:依赖注入
@Qualifier:依赖查找 / 指定注入 Bean 名称
@Component:通用组件标记
@Service:业务逻辑层(Service)
@Controller:Web 控制层
@RequestMapping:SpringMVC 请求映射
关键:依然是 XML 配置驱动 虽然有了大量注解,但必须依靠 XML 才能生效:
<!-- 开启注解处理器 → 让 @Autowired 等注解生效 -->
<context:annotation-config/>
<!-- 扫描包下的注解类,自动注册为Bean -->
<context:component-scan base-package="com.example"/>
<context:annotation-config/>:注册注解处理器,使注解生效<context:component-scan/>:扫描包路径,把@Component/@Service/@Controller类自动注册成 Spring Bean- 替代了一部分手写的
3.0
使用 AnnotationConfigApplicationContext 加载
去除了xml的方式
纯注解 + 配置类 = 彻底抛弃 XML
@Configuration 去xml化
核心目的是:把bean对象如何更加便捷的方式去加载到Spring IOC容器中
Component-Scan - @Service @Repository @Controller
Import
Enable模块驱动 启动自动配置

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,完成模块的初始化和装配。
先注册后置处理器 → 再统一扫描、解析、生效注解
@EnableScheduling
@Import(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
- 谁在注册任务
- 任务执行器是谁
只要开注解,就能用 → 这就是自动装配
- 模块化装配:@EnableXXX = 启动一个模块
- @EnableScheduling → 开启定时任务
- @EnableAsync → 开启异步
- @EnableTransactionManagement → 开启事务
- @EnableCaching → 开启缓存
模式完全统一:一个注解启动一套功能 = 自动装配的标准模型
ScheduledAnnotationBeanPostProcessor 是 Spring 定时任务的核心中枢:它是一个 Bean 后置处理器,在 Bean 初始化之后扫描 @Scheduled 注解,解析任务规则,注册并管理所有定时任务,在容器初始化完成后统一启动。它通过后置处理 + 注解驱动 + 自动注册,实现了完全无配置、开箱即用的定时任务能力,是 Spring 自动装配思想最早期、最标准的实践模型。
@EnableScheduling→ 注册 ScheduledAnnotationBeanPostProcessor → 后置处理扫描@Scheduled→ 解析、注册任务→ 容器启动 → 任务自动执行
4.0
Spring 4.x @Conditional(条件装配)
@Conditional 是 Spring 4.0 引入的条件开关注解 ,核心是在 Bean 注册前做条件判断 ,满足才注册、不满足直接跳过;它把 Spring 3.x 的 "注解驱动" 推进到按需驱动 ,是 Spring Boot 自动配置的底层基石。
java
// 自定义条件: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.0
@Indexed ------ 给组件扫描做 "索引",大幅提速
@Indexed 是 Spring 5.0 推出的「编译时组件索引」,用来解决 Spring 项目变大后,启动时 component-scan 扫描太慢的问题。
它的核心思想:不再启动时遍历所有 class 文件 → 编译时就生成索引 → 启动直接读索引 → 极快加载 Bean
- 你写代码
java
运行
@Service public class UserService {}
- 编译阶段(还没运行)
@Indexed扫描到这个类有组件注解自动写入文件META-INF/spring/components.idx内容:plaintext
com.xxx.UserService=org.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扫描,写入加入

java
//
// 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 RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, 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")
@EnableAutoConfiguration
@Import({AutoConfigurationImportSelector.class})
AutoConfigurationImportSelector
这段代码 只干一件事:
去 spring.factories 里,把所有 EnableAutoConfiguration 的类读出来!
把 RedisAutoConfiguration 从 spring.factories 里读出来,交给 Spring 去注册 Bean!
java
protected List<String> getCandidateConfigurations(...) {
// 1. 去读 spring.factories 文件
List<String> 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
- 拿到 RedisAutoConfiguration
- Spring 自动注册
RedisTemplate - 你直接
@Autowired
自写探究
一个模块同时包含:
- 自动配置
- 配置属性
- 核心功能
- starter 依赖
src
├── main
│ ├── java
│ │ └── com/demo/redis
│ │ ├── autoconfig
│ │ │ └── DemoRedisAutoConfiguration.java
│ │ ├── properties
│ │ │ └── DemoRedisProperties.java
│ │ ├── core
│ │ │ └── DemoRedisClient.java
│ │ └── annotation
│ └── resources
│ └── META-INF
│ └── spring
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
@EnableAutoConfiguration
↓
读取 spring.factories
↓
加载 RedissonAutoConfiguration
↓
创建 RedissonClient
↓
放入 IOC
↓
用户直接注入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.1.RELEASE</version>
<optional>true</optional>
</dependency>
| 依赖 | 作用 |
|---|---|
| spring-core | Spring核心 |
| spring-context | IOC容器 |
| spring-beans | Bean管理 |
| spring-aop | AOP |
| spring-expression | SpEL |
| logback | 日志 |
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.1</version>
</dependency>
真正的 Redis 客户端
| 功能 | 类 |
|---|---|
| 分布式锁 | RLock |
| 延迟队列 | RDelayedQueue |
| 阻塞队列 | RBlockingQueue |
| Map缓存 | RMap |
| Set缓存 | RSet |
| 原子类 | RAtomicLong |
| 限流器 | RRateLimiter |
| 布隆过滤器 | RBloomFilter |
| 读写锁 | RReadWriteLock |
spring-boot-configuration-processor
生成配置提示元数据
spring-boot-starter
↓
提供自动配置能力
redisson
↓
提供Redis客户端能力
configuration-processor
↓
提供IDEA配置提示c
java
package com.gupaoedu.redisson;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 咕泡学院,只为更好的你
* 咕泡学院-Mic: 2227324689
* http://www.gupaoedu.com
*
* @author cxyck*/
@ConditionalOnClass(Redisson.class) //条件装配
@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
public class RedissonAutoConfiguration {
@Bean
RedissonClient redissonClient(RedissonProperties redissonProperties){
Config config = new Config();
String prefix="redis://";
config.useSingleServer().
setAddress(prefix+redissonProperties.getHost()+":"+redissonProperties.getPort()).
setConnectTimeout(6000);
return Redisson.create(config);
}
}
java
package com.gupaoedu.redisson;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author cxyck
*/
@ConfigurationProperties(prefix = "gp.redisson")
public class RedissonProperties {
/**
* Redis地址
*/
private String host = "127.0.0.1";
/**
* Redis端口
*/
private Integer port = 6379;
/**
* Redis密码
*/
private String password;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
java
{
"properties": [
{
"name": "gp.redisson.host",
"type": "java.lang.String",
"description": "redis的服务器地址",
"defaultValue": "localhost"
},{
"name": "gp.redisson.port",
"type": "java.lang.Integer",
"description": "redis服务器的端口",
"defaultValue": 6379
}
]
}
java
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.gupaoedu.redisson.RedissonAutoConfiguration