前言:
SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作。
在讲springboot自动装配原理之前,我们需要知道一个在springboot项目中引入第三方依赖的方法:
引入第三方依赖的方法:
1:第一种方式:通过扫描第三方依赖的包名
@ComponentScan({"com.itheima","com.example"})
直接在启动类上加入这个扫描,不过这也有一个很大得问题,就是以后包多了,这个写起来可辛苦
2:第二种方式:通过Import关键字
@Import({TokenParser.class, HeaderConfig.class})//导入普通类
@Import({HeaderConfig.class})//导入配置类
@Import({MyImportSelector.class})//导入ImportSelector接口实现类
这也是后面springboot自动装配得底层注解。
在springboot项目中引入第三方依赖:
在讲如何引入第三方依赖之前,我们先讲第三方依赖或者说叫第三方Bean是什么?
第三方依赖是指项目所需要的外部库或框架,这些依赖并不是项目自带的代码,而是由其他开发者或组织维护的库,就像我们在项目中需要使用什么工具,第一步都是先引入这个工具的依赖
讲完这个,来介绍一下项目的准备工作。
我的项目中的java代码都在 spring-boot-tlias中
tlias-parent是父工程,专门做依赖的版本管理的,这个在maven那篇文章有提及
tlias-utils就是我这个项目背景中的第三方依赖,这也是一个工具项目。
springboot自动装配源码分析:
直接进入这个springboot的这个启动类注解
进来之后,会看到好多注解,上面四个是元注解,我们不关心
我们重点看
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
这三个注解。
第一个@SpringBootConfiguration
我们点进去之后,我们就会发现这里也有一个@Configuration注解,说明springboot的启动类也是一个配置类,也可以在启动类中添加Bean对象
第二个@ComponentScan
这个顾名思义就是用来组件扫描
这个扫描的范围是:SpringBoot主启动类的同级路径及子路径
第三个@EnableAutoConfiguration这个才是自动装配的主角
点进去看到有一个@Import注解,这个注解我们知道,就是导入第三方Bean的注解
导入什么嘞?
导入后面那个什么{AutoConfigurationImportSelector.class},
我们再点进去看
{AutoConfigurationImportSelector.class}
这个类实现了ImportSelector这个接口并且重写了selectImports这个方法
selectImports这个方法的作用就是用来返回的是要加载的Config配置文件的全包名列表,通过返回这个全包名列表,我们就能自动装配上这些配置文件下定义的bean对象,从而达到了自动装配的目的
我们既然已经有了这个思路,我们就可以看这个方法的返回值了:
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
然后我们目光就锁定在了这个autoConfigurationEntry上
点进 this.getAutoConfigurationEntry(annotationMetadata);
点进来之后就是这样的
有点长,我们先看返回值
返回值里面有两个变量:configurations和exclusions
我们再去上面找:
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
this.getCandidateConfigurations(annotationMetadata, attributes);
点进来之后是这个样子
我们重点看一下那一句断言:
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中找不到自动配置类。如果您正在使用自定义打包,请确保该文件是正确的
我们从这里再结合spring的一些知识
spring中的bean的配置都是在一个配置文件中的,所以
我们可以猜想,这也可能就是一个配置文件
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
我们跟着这个路劲进去一看,这个文件中就是很多的全类名
这里也稍微说一下:spring.factories
这里面也有很多全类名,
不过好像是在springboot3之后,这里面的文件就被弃用了,
我们看上面那句断言也能知道。
所以,自动装配的本质原理就是,springboot帮我们写好了配置文件在这个spring.factory中,然后自动读取。
自定义starter:
什么是自定义starter,并且为什么要定义自定义starter?
在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot 的 starter。
常见的自定义starter:阿里云OSS,JWT令牌,这些功能模块,我觉得也可以理解为工具类
为什么我要把这个自定义starter放在这个spingboot的自动装配机制后面,其实这个自定义starter就是利用了springboot的自动装配机制
我们点开项目的外部库:
我们可以看到,我们springboot官方在引入这些我们常见的依赖的方式都差不多
都有两个功能模块:自动配置功能,依赖管理功能
所以我们接下来也模范这个模式来完成一个:阿里云OSS操作工具类自定义starter的配置
阿里云OSS操作工具类自定义starter的配置:
1:创建 aliyun-oss-spring-boot-starter 模块
2:创建 aliyun-oss-spring-boot-autoconfigure 模块,在starter中引入该模块
3:在 aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
大致流程就是这三步,不过里面还是有很多细节的
1:创建 aliyun-oss-spring-boot-autoconfigure 模块:
创建完这个autoconfigure之后
我们需要把OSS操作的类给导过来
1:AliOSSUtils工具类:
/**
* 阿里云 OSS 工具类
*/
@Data
public class AliOSSUtils {
private AliOSSproperties aliOSSproperties;
/**
* 实现上传图片到OSS
*/
public String upload(MultipartFile file) throws IOException {
String endpoint = aliOSSproperties.getEndpoint();
String accessKeyId = aliOSSproperties.getAccessKeyId();
String accessKeySecret = aliOSSproperties.getAccessKeySecret();
String bucketName = aliOSSproperties.getBucketName();
// 获取上传的文件的输入流
InputStream inputStream = file.getInputStream();
// 避免文件覆盖
String originalFilename = file.getOriginalFilename();
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
ossClient.putObject(bucketName, fileName, inputStream);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}
这里如果注释上面有@Component,可以删掉
因为最后这个工具类会在自动配置类中做为Bean对象返回,所以不需要交由IOC容器管理
2:AliOSSproperties属性类:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSproperties {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucketName;
}
这个就是使用阿里云的时候需要的一些变量。
3:定义自动配置类:
@Configuration
@EnableConfigurationProperties(AliOSSproperties.class)
public class AliOSSconfiguration {
@Bean
public AliOSSUtils aliOSSUtils(AliOSSproperties aliOSSproperties){
AliOSSUtils ossUtils = new AliOSSUtils();
ossUtils.setAliOSSproperties(aliOSSproperties);
return ossUtils;
}
}
@Configuration注解来告诉springboot这是一个配置类
@EnableConfigurationProperties用来将配置文件中的属性映射到这个AliOSSproperties类,这个就是属性类
还有就是@Bean注解,将这个方法的返回值注册成一个bean对象交由IOC容器管理
还有一个注意点就是:工具类中:private AliOSSproperties aliOSSproperties;
有调用这个属性类,所以,你在返回这个对象的时候,你得给这个工具类设置好aliOSSproperties
要不然就会报经典得NPE,空指针异常
到此,这个autoconfigure模块就算创建完了
2:创建 aliyun-oss-spring-boot-starter 模块
这个倒比较简单
这个starter模块需要在pom文件中导入上面得autoconfigure模块
这里有一个坑:
我们需要想pom文件里面得依赖都来自于maven仓库。
所以,我们这样直接导入是会报找不到依赖得
The POM for com.aliyun-oss:aliyun-oss-autoconfigure:jar:0.0.1-SNAPSHOT is missing, no dependency information available
所以,解决办法就出来了,我们应该把我们刚刚写好得autoconfigure得模块导入到maven仓库中,
直接install即可
同理,我们也可以设想,如果说我们需要在后面得模块直接导入starter,我们也同时需要将starter模块也install,这样别的模块才能从maven仓库中找到。
3:在 aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
我们从上面得自动装配原理中也能指定,你要想把这aliOSSutils变成bean对象
需要在META-INF/spring/xxxx.imports配置文件中写入全类名,这样springboot才会自动扫描装配
又回到我上面说过得一个点
如果你是springboot2,你还可以写在一个spring.factory文件中,如果是springboot3,就只能写在 org.springframework.boot.autoconfigure.AutoConfiguration.imports这个配置文件中
至此,在项目中如果想使用这个starter,直接导入依赖即可