Spring的核心基石
IoC、DI、AOP
Inversion of Control(控制反转)
控制反转是一种设计思想, 类A需要创建类B时,传统方式在类A里new B(),B的生命周期由A控制,IOC使控制权交到Spring容器里, 类A等待Spring将装配好的类B传递给它。
Dependency Injection(依赖注入)
依赖注入是控制反转的具体实现方式,Spring容器在运行期间,动态地将依赖关系注入到对象中。
Bean
由Spring IoC容器实例化、组装和管理的对象,依赖注入的对象
IoC容器
应用启动时,容器会读取配置(注解或XML),将所有需要的Bean实例化并放在仓库里,当某个组件需要调用其他组件时,直接从仓库里按需分配
Aspect-Oriented Programming(面向切面编程)
AOP用来处理与业务逻辑无关,复用量大的代码,比如:日志记录、鉴权、数据库事务管理。
AOP的底层原理是Dynamic Proxy(动态代理),Spring会在运行时为原本的Bean生成一个“代理对象”,外部调用业务方法时,实际上调用了代理对象,代理对象在执行核心逻辑之前或之后,自动插入日志、事务等“切面”逻辑。
注解
- @Configuration 告诉Spring,这个类是个配置中心
- @ComponectScan 告诉Spring,去哪里寻找被打上标记的组件
- @Service 将类实例化为业务逻辑层的Bean
- @Controller 将类实例化为接口控制层的Bean
- @Autowired 依赖注入 用于一个类的某个属性前
- @Qualifier 当Spring注入时找到多个Bean类时,Qualifier注解说明精确匹配 example:@Qualifier("class")
- @SpringBootApplication
使用Spring Context构建IoC容器
手写纯Spring容器,添加SpringContext依赖
创建业务类:
- 接口MessageService,包含sendMessage()方法
- 实现类EmailMessageService,实现sendMessage()方法,打印一行输出
- UserController类,内部包含一个MessageService类型的属性
注解驱动:
- EmailMessageService上添加@service注解
- UserController上使用@Controller注解,并在MessageService属性上实现@AutoWired依赖注入
配置与启动
- 创建AppConfig配置类,添加@Configuration,@ComponectScan注解便于Spring扫描创建Bean类
- 创建带main方法的启动类,使用AnnotationConfigApplicationContext的构造函数加载AppConfig.class,从容器中获取UserController的Bean(使用'getBean(UserController.class)'),并调用方法
Spring容器只包含对象的初始化问题。
SpringBoot简化配置过程 SpringApplication.run(Application.class, args);
启动与生命周期回调
@SpringBootApplication
SpringApplication.run(Application.class, args);SpringApplication的run方法的执行过程如下:
1.准备环境,事件监听器等前期工作
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext,applicationArguments);2.创建IoC容器上下文
ConfigurableApplicationContext content = createApplicationContext();3.准备上下文并刷新容器(完成包扫描、Bean的实例化、@Autowired注入)
refreshContext(content);4.容器刷新后处理逻辑
afterRefresh(context, applicationArguments);5.调用所有的Runners
callRunners(context, applicationArguments);6.启动完成,返回上下文
return context;refreshContext() Spring容器启动,根据注解将类实例化并放入容器,完成依赖注入callRunners() SpringBoot特有的扩展逻辑。容器刷新完后,SpringBoot会主动向容器索要特定类型的Bean并执行它们。如实现了CommandLineRunner和ApplicationRunner函数式接口的Bean类,在SpringBoot即将启动完成的最后一步被调用。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeanOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeanOfType(CommandLineRunner.class).values());
//按Order注解排序执行
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if(runner instanceof ApplicationRunner applicationRunner) {
applicationRunner.run(args);
}
if(runner instanceof CommandLineRunner commandLineRunner) {
commandLineRunner.run(args.getSourceArgs());
}
}
}自动装配机制
在pom.xml里引入依赖,SpringBoot就会自动配置好相应的组件,而无需手动写配置类。
自动装配内置Tomcat服务器:
- 依赖传递:准备ClassPath
在pom.xml中引入spring-boot-starter-web时,Maven的依赖传递机制会自动下载并引入spring-boot-starter-tomcat.此时,Tomcat相关的类(如org.apache.catalina.startup.Tomcat)存在于 项目的ClassPath(类路径)中。 - 读取进口清单(SPI机制)
应用启动,AutoConfigurationImportSelector开始工作,它去类路径下所有的JAR包中寻找特定文件,文件路径为:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
(文件位于spring-boot-autoconfigure-xxx.jar) - 加载自动配置类
文件中列出上百个自动配置类的全限定名。其中有一个专门负责Web服务器配置的类:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,引擎会将这个类加载进内存并进行条件判断。 - 条件注解的精准过滤(@Conditional) 引擎查看ServletWebServerFactoryAutoConfiguration类,根据注解进行条件判断:
@ConditionalOnClass({ServletRequest.class}):要求类路径下必须有Servlet相关的类@ConditionalOnWebApplication:要求当前是一个Web应用@ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}):要求类路径下必须有Tomcat的核心类
- 动态注册Bean 由于第一步将Tomcat类存在了类路径中,因此条件判断通过,SpringBoot自动配置Tomcat所需的Bean(
TomcatServletWebServerFactory)注册到Spring IoC容器。容器在刷新时,会调用这个工厂Bean来启动真实的内嵌Tomcat进程。