目录
5.ImportBeanDefineRegistrar(6的升级版)
六.springboot比spring好在哪?它为啥方便了?
一.bean的加载方式(8种)
1.
2.
3.@import(普通类,配置类)
好处:被导入的类不用声明成bean
4.ImportSelector(可以做判定)
为什么要这么折腾一圈呢?
元数据,导入的类的元数据。哪里用了@import注解谁就是这个元数据
这种方式加载bean,不仅可以加载bean,还可以做判定。这个东西selector选择器,可以进行一系列的判定,判定完成后,再决定是否加载指定的bean。@import在哪个配置文件上,检测的就是谁。
5.ImportBeanDefineRegistrar(6的升级版)
上一个只能加载bean,这一个可以修改bean了,也可以说是管理bean。
二.自动装配
ImportSelector 可以进行各种条件的判定,判定完毕后,决定是否加载指定的bean
有什么条件呢?
可以得出,它不仅能加载bean。还可以控制加载谁,可以根据条件动态的加载bean,哪个配置类导入了它(@import),它就检测哪个配置类。
ImportBeanDefinitionRegistrar
这个对比上一个方法,你可以管理bean了,上一个方法你只能输个全限定名就给你加载了,但这个方法你可以动bean了。因为你拿到了Beandefinition。
举一个例子:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyBeanRegistrar.class) // 👈 关键!
public @interface EnableMyService {
}
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 1. 构建一个 BeanDefinition(通过 BeanDefinitionBuilder)
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(MyService.class); // 指定要注册的类是 MyService
// 2. 手动调用 registry.registerBeanDefinition(...) 注册它
registry.registerBeanDefinition("myService", builder.getBeanDefinition());
// 👆 就是这行代码!!!体现了“手动注册 BeanDefinition”
}
@Configuration
@EnableMyService // 👈 一加这个注解,就会触发导入 MyBeanRegistrar
public class AppConfig {
}
Spring 在启动时,会:
- 解析到
@EnableMyService
- 看到它使用了
@Import(MyBeanRegistrar.class)
- 就会把 MyBeanRegistrar 这个类加载进来,并调用它的 registerBeanDefinitions() 方法
- 在这个方法中,你调用了
registry.registerBeanDefinition(...)
,也就是 手动告诉 Spring:请把某个类(比如 MyService)注册为一个 Bean,它的定义是啥啥啥- Spring 拿到这个 BeanDefinition 后,就会根据它去实例化和管理真正的 Bean 对象
@Import(ImportBeanDefinitionRegistrar.class) 的作用就是:在 Spring 启动时,把一个实现了 ImportBeanDefinitionRegistrar 接口的类加载进来,然后调用它的 registerBeanDefinitions 方法,让你有机会通过编程的方式,手动向 Spring 容器注册 BeanDefinition,从而控制 Bean 的加载。
你注册了 BeanDefinition,Spring 就知道:“哦!我要创建这个 Bean!”,然后它就会去实例化和管理它。
Spring 容器本质是一个 Bean 工厂,它管理的不是对象,而是 Bean 的定义(BeanDefinition)。 BeanDefinition 是 Spring 中描述一个 Bean 的配置信息(比如类名、作用域、构造方法等)的对象,它相当于 Bean 的“配方”或“元数据”。
Spring 不直接操作你的类,而是先根据 BeanDefinition 去实例化和管理 Bean。
所以,你只要手动注册一个 BeanDefinition(告诉 Spring 这个类要被管理),Spring 就会按照这个定义去创建和管理 Bean,从而实现你想要的 Bean 注册和控制。
BeanDefinitionRegistryPostProcessor
====================================================
@EnableAutoConfiguration
1.扫描包及其子包
2.读取自动配置类
3.注册符合条件的配置类
- @Import(AutoConfigurationPackages.Registrar.class)
得到了一个com.itheima。需要扫描下面的东西,扫哪里就通过这个,扫描的包路径。说白了就是springboot怎么知道要扫描哪些包,就是设置当前所在的包作为扫描包,后续针对当前的包进行扫描。
- @Import(AutoConfigurationImportSelector.class)
分为三大类:
1.Aware:想用哪些,实现这些aware接口就可以了
2.ordered:加载顺序,有时候加载一个bean需要依赖某一个bean,这个bean加载了我才加载。
3.Deferred :推迟加载
获取META-INF/spring.factories。这个东西是啥?初始默认加载的一大堆东西。
流程
1.springboot启动,@SpringBootApplication里面有一个@EnableAutoConfiguration
2.
@EnableAutoConfiguration
的作用是告诉 Spring Boot:“请开始自动装配!”
它的底层通过 @Import(AutoConfigurationImportSelector.class)
实现,关键类是:
-
AutoConfigurationImportSelector
:负责从类路径中筛选并加载自动配置类。(按条件加载)
3.AutoConfigurationImportSelector
的工作流程如下:
读取所有候选的自动配置类
- 从 所有依赖的 JAR 包 中查找
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件(Spring Boot 2.7+ 版本)。
其中某一个自动配置类被列在文件中,并不是无条件加载,而是需要通过@conditional系列注解的判断。
@ConditionalOnClass(DataSource.class)
:类路径下必须有DataSource
类(比如引入了spring-jdbc
依赖)。@ConditionalOnProperty(name = "spring.datasource.url")
:配置文件中必须配置了数据库 URL。@ConditionalOnMissingBean(DataSource.class)
:容器中不能已经存在DataSource
的 Bean(避免重复注册)。
注册符合条件的自动配置类
- 通过
BeanDefinitionRegistry
将筛选后的自动配置类注册到 Spring 容器中。BeanDefinitionRegistry
.registryBeanDefinition("beanName",bean.class)
- 这些自动配置类内部通常会定义一些 Bean(如
DataSource
、DispatcherServlet
),从而完成自动装配。
总结
初始化环境:自定义的bean 如@bean注解 以及导入的坐标 maven,形成初始化的环境
设置集A:扫描出的META-INF中全部文件,但不是真的加载,还需要看条件满不满足。与初始化的环境进行比对,满足就加载,不满足就不加载。
设置集B:加载满足加载条件技术的配置文件,有带默认值的,也有不带的,完全取决于给你配置成什么样。默认加载,如果想覆盖,你就修改即可。
三.自定义starter
四.启动流程
五.Maven
1.maven有什么用
2.基础概念
1.仓库
2.坐标
3.依赖管理
1.依赖传递
可选依赖:optional:不被别人知道我有这个
排除依赖:exclude:主动不要别人这个
依赖范围:scope:
4.多模块开发
1.聚合
如果一个模块更新了,出现问题了。
2.继承
不兼容了,出现问题。怎么解决?用一个父类统一写上(也就是依赖管理),后面的去继承它就好了,后续的工程就不需要再写版本了,以此达到避免依赖冲突的问题。
3.属性(版本统一的重要性)变量名
后面依赖中的version就可以写成${...}了
4.版本管理
5.资源配置
6.多环境开发配置(生产,开发,测试环境不同)
7.私服
1.仓库的类别
创建仓库,并放到仓库组中。比如release,snapshots等
2.本地仓库访问私服
配置本地仓库的setting,第一个用户名和密码,让本地仓库有权限访问我们的私服
第二个是下载的地址,一个仓库从中央仓库中拿(阿里云),其余的全从仓库组来
3.上传项目到私服中
package:只是做一个打包,生成在开发路径下的
install:上传到本地仓库
deploy: 上传到私服中(发到哪就看你上面配置的是哪)
六.springboot比spring好在哪?它为啥方便了?
简化spring应用的初始搭建以及开发过程。
1.parent(仅仅是定义了还没使用哦)
几个工程project都依赖了相同的东西,写的话就重复了。
拿一个project-dependency一个pom统一管理,同时将版本拆出去变成maven的属性,dependency中直接引用就可以了。
那具体是怎么做的呢?
又继承这个dependency
这个dependency定义了一系列的坐标属性properties
而且定义了一个依赖管理dependencyManagement,引用了上面的版本。
所以我们在引入时就不用写坐标了,不用管坐标了。避免了依赖冲突现象的发生。
2.starter(starter里面有若干东西)
一个starter包含了若干个依赖的信息。实现了快速的配置,减少依赖配置的目的