SpringBoot中怎么定义一个stater?自动装配规则到底是怎样的?

问题引出

最近实习发现公司项目中有spring.factories文件,是用来定义starter的,让这个模块可以被其他模块引入pom依赖后直接使用,那为什么还必须用spring.factories配置才能被其他模块使用,直接引入依赖不能直接使用吗?

答案是能用,但是只能使用这个模块中的非Bean,也就是非spring容器中的类(例如工具类的静态方法)。这个模块定义的spring Bean不能用,会报找不到该Bean的错误,也就是扫描不到该模块中定义的Bean,比如下面例子:

在demo模块中直接使用starter模块的server1和server2两个bean,会报错:

为什么扫描不到?

SpringBoot默认扫包规则:在不自己定义scanBasePackage参数或scanBasePackageClasses参数或@ComponentScan扫包规则下,SpringBoot默认约定只会默认扫描主程序包下及其子包下的bean

所以,你通过pom引入的第三方依赖,人家定义的包结构大概率和你的包结构不一样(包结构一般都是公司内部自定义的)。所以,依赖引入来的Bean就扫描不到!自然也就找不到该Bean。

使用@ComponentScan注解把所有包都列举出来,如果引入的依赖多了,显然不太现实。

那怎么办呢?怎么定义一个让别人直接能使用的stater呢?

starter怎么写

参考spring-boot-autoconfigure这个包的规则(其实这个包加上@SpringBootApplication注解就是springboot的自动装配原理): 

1. 添加spring-boot-stater依赖(因为这个依赖里有spring-boot-autoconfigure这个依赖):

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

2.定义configuration类,在里面创建需要的bean:

3.在resource目录下新建目录META-INF/spring,并添加org.springframework.boot.autoconfigure.AutoConfiguration.imports文件:

文件内容就是我们的的配置类:

然后就可以直接将该依赖给其它项目使用。 

如果需要像springboot官方的starter一样,导入一个starter之后在yml中写一些配置就能直接改变bean的属性值(yml中的配置其实就是一个个的bean对象,你改变配置其实就是在改bean的属性值),需要使用@ConfigurationProperties将bean和和配置文件绑定起来,再在configuration类上添加

@EnableConfigurationProperties注解。就能做到改yml配置文件就能修改bean的属性值,例如:

其实spring.factories文件这种做法其实在springboot3之后官方已经不再推荐使用,而是推荐使用

org.springframework.boot.autoconfigure.AutoConfiguration.imports

文件这种方式。

为什么不推荐使用spring.factories了

把作者的话翻译过来就是:

使用spring.factories查找自动配置类会给我们的本地工作带来问题。我们最初使用它是因为代码已经可用,但我们希望在2.7中提供一个替代方案,并在3.0中停止使用spring.factories进行自动配置。

这句话中的navite是关键,它并不是本地的意思。而是cloud native中的native。一切为了云原生!

springboot3中一个很大的特色就是增加了很多对云原生的支持!

我们知道,云原生时代中,最重要的是什么?启动速度。那Java如何提升启动速度?AOT编译+云原生镜像。可是,传统方法使用spring.factories依赖于运行时扫描和加载自动配置类,这么做效率肯定不高。不适合云原生!

相比之下,使用org.springframework.boot.autoconfigure.AutoConfiguration.imports这种方式,允许在编译时确定自动配置类,减少了运行时开销,并使得像GraalVM这样的工具更容易分析和编译Spring Boot应用到原生映像。这种方法可以带来更快的启动时间和更低的内存消耗,这对于从可扩展性和效率受益的云原生应用至关重要。

SpringBoot自动配置原理

每个spring-boot-starter-xxx能包含spring-boot-sarter,而spring-boot-starter中又包含spring-boot-autoconfigure。spring-boot-configure中包含了所有所有场景的配置类,es的、redis的、jdbc的......等等等:

每个自动配置类大概都长这样:

并且该模块中同样有org.springframework.boot.autoconfigure.AutoConfiguration.imports文件:

在该文件中把所有的xxxAutoConfiguration全都写进来了:

也就是说,只要这个包下的所有类都能生效,那么相当于SpringBoot官方写好的整合功能就生效了。但是SpringBoot默认却扫描不到 spring-boot-autoconfigure下写好的所有配置类默认只扫描主程序所在的包

然后就看主程序的@SpringBootApplication注解了:

这个注解由三个注解组成@SpringBootConfiguration@EnableAutoConfiguratio@ComponentScan。@SpringBootConfiguration和@Configuration功能差不多,都是将类定义为配置类,@ComponentScan注解默认扫主程序所在的包的。关键就是@EnableAutoConfiguratio:

 并且这个注解中又使用了@Import导入了AutoConfigurationImportSelector类,这个类就是自动导入org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中的配置类:

(在springboot3之前是spring.factories:)

 至此,springboot就能把非主程序包的配置类全加载进来了。但是其实并不是全部都加载进来,而是按需加载!原因就在于每个配置类上都加了@ConditionOnxxx之类的注解,只有在这个条件成立的时候才会加载,例如:

拿@ConditionOnClass(JakartaWebServlet.class)举例,只有JakartaWebServlet这个类存在时也就是这个依赖被导入时才加载。也就实现了你导入哪个依赖就加载哪个配置类,而不是全部都加载进来!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值