Skip to content

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并执行它们。如实现了CommandLineRunnerApplicationRunner函数式接口的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服务器:

  1. 依赖传递:准备ClassPath
    在pom.xml中引入spring-boot-starter-web时,Maven的依赖传递机制会自动下载并引入spring-boot-starter-tomcat.此时,Tomcat相关的类(如org.apache.catalina.startup.Tomcat)存在于 项目的ClassPath(类路径)中。
  2. 读取进口清单(SPI机制)
    应用启动,AutoConfigurationImportSelector开始工作,它去类路径下所有的JAR包中寻找特定文件,文件路径为:META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
    (文件位于spring-boot-autoconfigure-xxx.jar)
  3. 加载自动配置类
    文件中列出上百个自动配置类的全限定名。其中有一个专门负责Web服务器配置的类:org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,引擎会将这个类加载进内存并进行条件判断。
  4. 条件注解的精准过滤(@Conditional) 引擎查看ServletWebServerFactoryAutoConfiguration类,根据注解进行条件判断:
  • @ConditionalOnClass({ServletRequest.class}):要求类路径下必须有Servlet相关的类
  • @ConditionalOnWebApplication:要求当前是一个Web应用
  • @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class}):要求类路径下必须有Tomcat的核心类
  1. 动态注册Bean 由于第一步将Tomcat类存在了类路径中,因此条件判断通过,SpringBoot自动配置Tomcat所需的Bean(TomcatServletWebServerFactory)注册到Spring IoC容器。容器在刷新时,会调用这个工厂Bean来启动真实的内嵌Tomcat进程。

内嵌容器与Web

数据与外部集成

扩展与生产就绪