当前位置: 首页 > article >正文

SpringBoot知识点及其源码解析(1)

自动配置

以web启动器为例,在spring-boot-starter-test-3.4.3.pom文件整合了一系列的依赖,那么当启动程序后会不会进行自动配置?当获取到这个容器后,可以从容器中获取所有bean的名字,此时就可以在控制台发现很多bean的名称,都是自动配置进来的。

@SpringBootApplication
public class Demo1Application {

    public static void main(String[] args) {
        // 初始化IOC容器
        ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(Demo1Application.class, args);
        // 从容器中获取所有的bean的名字
        String[] beanDefinitionNames = configurableApplicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }

}

在这里,也可以发现自定义的bean,这是由于@RestController这个注解,等价于@Controller+@ResponseBody,它标记类为REST控制器,即标识一个类为SpringMVC控制器,处理HTTP请求,与传统的@Controller相比,直接返回数据,不返回视图。要使用注解管理类的化,前提要开启包扫描,在启动类的@SpringBootApplication注解下有@ComponentScan,这个注解行包扫描,规则是扫描当前的类(Demo1Application)的目录(demo1)及其子目录(controller)

  • 如果定义了某一个场景的启动器,那么项目在加载的时候,会开启对这个启动器的自动配置,会将这个启动器所属依赖里面的相关组件全部交给ioc容器进行管理。
  • 自定义组件,通过@ComponentScan注解进行包扫描,规则是扫描当前的类的目录及其子目录。
  • springboot不会将所有场景的资源进行自动配置,采取的是按需加载的方式进行自动配置,只有导入对应场景的启动器,那么相关组件才能被管理到ioc容器中

注解

@Configuration

管理bean的方式

  • xml的方式管理bean
  • 使用注解方式管理bean,@Component,@Controller,@Service,@Repository
  • 配置类

        @Configuration标识当前的类是一个配置类,类似于spring里的xml配置文件,@Bean像ioc容器添加组件,类似于xml文件中的bean标签,返回值类型是添加到容器组件的数据类型,可以在启动类进行ioc容器中获取bean之后打印,即可得到注入的类。

        被@Configuration修饰的配置类,也被交给容器进行管理,由于内部集成了@Conponent注解

MyConfig myConfig = context.getBean(MyConfig.class);
System.out.println(myConfig);
com.example.demo2.config.MyConfig$$SpringCGLIB$$0@7316523a

其中的SpringCGLIB表示这个配置类所属的bean是一个基于CGLIB字节码增强的代理对象

        在@Configuration注解内部有一个boolean proxyBeanMethods() default true;表示每个@Bean方法被调用返回的组件都是单例的,如果变为false的话,每个@Bean方法被调用的组件都是新创建的。

@Import

  • 在配置类上加入@Import(value={Animal.class})后在启动类获取bean的名称,得到com.example.demo2,pojo.Animal表示向容器中导入一个普通类的组件,组件名称是Animal的全限定名。
  • 也可以导入配置配置类,名称是配置类的名称
  • 导入ImportSelector接口实现的类
  • 导入ImportBeanDefinitionRegistrar接口实现的类
  • 总之,可以通过@Import注解向容器中导入一个组件

@Conditional

根据条件动态控制 Bean 的注册或配置类的解析。其核心作用是通过条件判断决定目标对象(如 Bean 或配置类)是否被 Spring 容器处理。SpringBoot在@ConditionalOnBean注解的集成上实现了细化,无需实现Condition接口,只需使用定义好的@ConditionalOnXXX注解,就会注入到IOC容器。例如@ConditionalOnBean(name = "cat"),表示容器中存在cat这个bean,当前@Bean注解修饰的组件才会被装配到容器中;@ConditionalOnMissBean(name = "cat"),表示容器中不存在cat这个bean,当前@Bean注解修饰的组件才会被装配到容器中。

@ImportResource

springboot 默认是不识别 xml 配置文件的,如果我们实在想在 springboot 项目中使用 xml 配置文件,需 要使用 @ImportResource 注解导入 xml 配置文件

配置绑定注解

在原生的spring中可以通过set方法或者构造方法进行注入,也可以基于注解的方式进行注入。

Set方法注入
<bean id="userService" class="com.example.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
</bean>
public class UserServiceImpl {
    private UserDao userDao;
    
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

构造方法注入
<bean id="userService" class="com.example.UserServiceImpl">
    <constructor-arg ref="userDao"/>
</bean>
public class UserServiceImpl {
    private final UserDao userDao;
    
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
}

基于注解的注入
public class UserServiceImpl {
    @Autowired
    private UserDao userDao;
}

那么在springboot中如何进行配置属性的自动绑定

  • @Value 注解手动进行绑定:@Value("${car.name}") private String name;

  • @Component+@ConfigurationProperties注解进行属性的自动绑定:@ConfigurationProperties(prefix="car") public class car {}

  • @Configuration+@EnableConfigurationProperties注解进行属性的自动绑定:在配置类上进行定义

依赖注入和自动绑定

自动绑定(通过@ConfigurationProperties注解实现功能)时将外部的配置(如application.yml)的属性自动映射到Java对象中,目的是简化配置管理。依赖注入时管理对象之间的依赖关系,由Spring容器负责创建对象并注入其所需的依赖,目的是为了减少代码之间的耦合度。

工作流程:启动类加载(@SpringBootApplication)-->  自动扫描文件下的自动配置类(AutoConfigurationImportSelector)--> 自动配置(SpringBoot检查条件注解,例如@ConditionalOnClass,满足条件才会实例化相应的bean并注入到ioc容器中)-->配置属性的绑定(@ConfigurationProperties进行标注配置属性) --> 依赖注入(构造器,setter方法或者注解)-->环境准备-->启动程序

springboot自动配置原理

包扫描规则原理

从前面可知,扫描的目录是启动器所在的目录及其子目录。

自动配置类的加载 

// annotationMetadata 中获取于@EnableAutoConfiguration相关的属性
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);  
// 获取所有候选的自动配置类的全限定名列表(只关注这个)
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 去除重复的配置类名称,避免重复加载
configurations = this.removeDuplicates(configurations);
// 获取注解中明确排除的那些自动配置类
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 验证排除的类是否确实存在于候选配置类列表中
this.checkExcludedClasses(configurations, exclusions);
// 将用户指定要排除的自动配置类从候选列表中移除
configurations.removeAll(exclusions);
// 过滤器进一步筛选配置类,可能是基于环境、条件注解等
configurations = this.getConfigurationClassFilter().filter(configurations);
// 通知关于即将导入的自动配置类和被排除的类的信息
this.fireAutoConfigurationImportEvents(configurations, exclusions);
// 包含了经过上述处理后的最终自动配置类列表以及被排除的类集合
return new AutoConfigurationEntry(configurations, exclusions);

其中的ImportCandidates.load(this.autoConfigurationAnnotation, this.getBeanClassLoader());是用以加载自动配置类的关键步骤,使用了ImportCandidates类来从classpath中读取指定的自动配置类列表。

  • this.autoConfigurationAnnotation: 这是一个指向@EnableAutoConfiguration注解的引用。在Spring Boot的上下文中,表示寻找与自动配置相关的类。

  • this.getBeanClassLoader(): 这个方法返回的是当前应用上下文使用的类加载器。类加载器是Java虚拟机用来查找和加载类的关键组件。在这里,它被用来定位classpath上的资源文件。

  • ImportCandidates.load(...): 这个静态方法会根据传入的注解(这里是@EnableAutoConfiguration)和类加载器来查找并读取相应的AutoConfiguration.imports文件。然后,它会解析该文件中的每一行作为全限定类名,并将这些类名收集到一个列表中返回

  • String location = String.format("META-INF/spring/%s.imports", annotation.getName());表示的就是路径

打个断点,就能得到name,因此总路径是INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

 由断言和上面的总路径可知进入D:\java\mvn_repository\org\springframework\boot\spring-boot-autoconfigure\3.4.3\spring-boot-autoconfigure-3.4.3.jar!\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports这里,就可以看到很多配置信息,

那么可以得出,当加载配置信息的时候,就是加载的这153项,下图的debug也可以证明

总结

自动配置类加载流程 

AOP

AOP是如何进行自动配置的,在D:\java\mvn_repository\org\springframework\boot\spring-boot-autoconfigure\3.4.3\spring-boot-autoconfigure-3.4.3.jar!\org\springframework\boot\autoconfigure\aop\AopAutoConfiguration.class路径下,有一个注解

@ConditionalOnProperty(
    prefix = "spring.aop",
    name = {"auto"},
    havingValue = "true",
    matchIfMissing = true
)

注解要生效,必须存在spring.aop开头的配置信息,在这个配置信息下,必须有一个auto属性,而且必须为true,在配置文件中的默认值为true,那么此时进行了自动的配置,下面进行验证

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
        String[] names = context.getBeanNamesForType(AopAutoConfiguration.class);
        System.out.println(names.length);
        for (String s : names) {
            System.out.println(s);
        }
    }
}

 在AopAutoConfiguration.class类下,有一个AspectJAutoProxyingConfiguration类,被@ConditionalOnClass({Advice.class})进行修饰,表示如果没有导入Advice.class这个类,表示这个注入不生效,Advice.class在import org.aspectj.weaver.Advice;包下,但是现在并不存在这个包,就是没有在pom.xml引入相关的依赖,那么AspectJAutoProxyingConfiguration类在容器中也是不存在的。代码进行验证报错,即组件没有教给容器管理

cache

导入CatchAutoConfiguration之前要做很多条件注入

DispatcherServletAutoConfiguration

在package org.springframework.boot.autoconfigure.web.servlet;下

 

 

总结 

  1. 自动配置类的名称xxxAutoConfiguration
  2. 自动配置类会开启信息的自动绑定,都会将定义的自动配置信息绑定到一个xxxProperties上面
  3. 自动配置类里面会通过@Bean注解 装配很多组件到ioc容器里面去(有很多条件装配)
  4. springboot永远以用户配置的组件为准,如果用户没有配置,就以springboot默认配置的为准
    @ConditionalOnMissingBean
  5. springboot很多配置信息都设置了默认值,如果用户修改,就以默认值为准,如果用户修改了,就以用户设置的值为准,例如:server.port

http://www.kler.cn/a/576147.html

相关文章:

  • 发行基础:热销商品榜单
  • 图形界面控件编程(iOS)
  • 机器学习——回归树
  • linux-mysql
  • C语言【进阶篇】之结构体 —— 从基础声明到复杂应用的进阶之路
  • 论文阅读笔记:TopoFR: A Closer Look at Topology Alignment on Face Recognition
  • CVE-2025-0392:JeeWMS graphReportController.do接口SQL注入漏洞复现
  • 图像生成-ICCV2019-SinGAN: Learning a Generative Model from a Single Natural Image
  • 小米安全攻防工程师面试题解析
  • 第6章 定时器计数器
  • 代码随想录算法营Day59 | 寻找存在的路径, 冗余连接,冗余连接II
  • 用DeepSeek学Android开发:Android初学者遇到的常见问题有哪些?如何解决?
  • 分类学习(加入半监督学习)
  • c# 修改邮件附件名称
  • Flask 打包为exe 文件
  • git如何解除远程仓库 改变远程仓库地址
  • fastapi+angular就业管理系统
  • 慕慕手记项目日记 2025-3-7 项目基本环境搭建
  • 如何用FFmpeg高效拉流(避坑指南)
  • 捣鼓180天,我写了一个相册小程序