springboot自动装配原理(源码分析)及自定义starter

前言:

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,直接导入依赖即可

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值