您现在的位置是:首页 >其他 >SpringBoot自动配置原理、手写一个xxx-spring-boot-starter网站首页其他
SpringBoot自动配置原理、手写一个xxx-spring-boot-starter
SpringBoot的自动配置是:当项目中使用了一个第三方依赖,如何将第三方依赖中的Bean加载到Spring的IOC容器中,我们就可以做到无需额外的配置,直接使用第三方jar中的Bean。
SpringBoot的理念是“约定大于配置”,只要按照SpringBoot约定的规则来提供第三方的jar,SpringBoot就可以自动扫描jar中的Bean加载到IOC容器中。
先要了解SpringBoot自动配置的原理,才能手写一个xxx-spring-boot-starter
SpringBoot自动配置的原理
当我们在SpringBoot的启动类上使用了@SpringBootApplication注解后,这个注解是一个复合注解
@SpringBootApplication
public class SpringBootTestMystaterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestMystaterApplication.class, args);
}
}
查看这个注解,会看见有一个@EnableAutoConfiguration的注解,这个注解是实现SpringBoot自动配置的关键注解.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
// ...
}
继续查看@EnableAutoConfiguration注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
// ...
}
此注解也是一个复合注解,在此注解中有一个@AutoConfigurationPackage注解,此注解能够实现此项目中启动类所在包及其子包下的Bean的自动注入
还通过@Import注解来导入一个AutoConfigurationImportSelector类,此类是实现第三方依赖中Bean注入的关键类
接下来说的是第三方依赖中要做好的配置
在第三方的依赖中,为了实现让SpringBoot自动配置本依赖,需要在此依赖中定义一个配置类,并使用@Configuration注解标注,在这个配置类中使用@Bean注解将需要注入的Bean实例化并提供出来
在此项目中的resources目录下的META-INF目录下新建spring.factories文件,此文件是一个类似于.properties
的文件,通过键值对的形式,value为使用了@Configuration的配置类的全限定名
以上就是第三方依赖需要做的配置
接下来继续回到本项目,导入第三方的starter依赖后,
当项目启动后,上述的AuthoConfigurationImportSelector类就会依靠一个叫做SpringFactoriesLoader的类,此类的作用是扫描所以jar中的META-INF/spring.factories
的文件,将所有文件中定义的配置类的全限定名返回,
当拿到这些第三方依赖的配置类,这些配置类中提供了要自动注入的Bean,就可以直接使用第三方依赖中的提供出来的Bean了
手写一个spring-boot-starter
1. 首先创建一个maven项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.liumingkai</groupId>
<artifactId>kkk-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.7.10</version>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2.创建一个需要自动注入的Bean
package com.liumingkai.service;
import org.springframework.beans.factory.annotation.Value;
/**
* @author 刘明凯
* @version 0.0.1
* @date 2023年4月23日 19:50
*/public class SayHello {
@Value("Mingkai Liu")
private String name;
public void sayHello(){
System.out.println("Hello , My name is " + name);
}
}
3.创建此项目的配置类,将需要注入的类提供出去
package com.liumingkai.auto;
import com.liumingkai.service.SayHello;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 刘明凯
* @version 0.0.1
* @date 2023年4月23日 19:50
*/@Configuration
public class MyConfiguration {
@Bean
public SayHello sayHello(){
SayHello sayHello = new SayHello();
return sayHello;
}
}
4. 在META-INF/spring.factories
文件中指明该项目配置类的全限定名
org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.liumingkai.auto.MyConfiguration
5.将项目打包到本地仓库(利用Maven的install命令)
6.在需要引用的项目中导入此依赖
<dependency>
<groupId>org.liumingkai</groupId>
<artifactId>kkk-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
测试自动注入是否成功
package com.liumingkai;
import com.liumingkai.service.SayHello;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBootTestMystaterApplicationTests {
@Autowired
private SayHello hello;
@Test
void contextLoads() {
hello.sayHello();
}
}
运行结果,发现成功注入