搞定SpringBoot的⾃动注⼊原理,⼀篇⽂章就够了
⽂章⽬录
前⾔
使⽤ springboot 进⾏项⽬开发时,⽆需各种配置⽂件,⽆需繁杂的 pom 坐标,只要⼀个 xxxApplication (启动类)就 run 起来了,那springboot 是怎么做到约定⼤于配置的?
⾃定义 starter
为什么要⾃定义 starter
在⽇常开发中,经常会有⼀些独⽴于业务的公共模块,如果多个⼯程中都可以复⽤这个公共模块的话,不需要⼿动拷贝到⼯程中,我们将公共的模块封装成⼀个个starter,复⽤的时候直接引⼊依赖即可,springboot为我们完成⾃动装配。
命名规则
springboot官⽅提供的 starter 以 spring-boot-starter-xxx ⽅式命名。官⽅建议⾃定义的 starter 使⽤ xxx-spring-boot-starter 的⽅式命名,以区分这两种 starter
⾃定义 starter 实现
1、新建空 project ,名为:hello-spring-boot-starter
2、新建⼦ modules,名为:hello-spring-boot-autoconfigure
3、hello-spring-boot-autoconfigure 中 pom引⼊依赖
<!--⾃动配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!--⽀持读取xml/properties⽂件配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
4、新建 HelloProperties 类
// 配置属性前缀
@ConfigurationProperties("my.hello")
public class HelloProperties {
private String name;
private Integer age;
private String hometown;
// getter setter toString 略
}
5、新建 HelloService 类
public class HelloService {
private String name;
private Integer age;
private String hometown;
public HelloService(String name, Integer age, String hometown){
this.name = name;
this.age = age;
this.hometown = hometown;
}
public String sayHello(String name){
"+ name;
}
public String helloWorld(){
return String.format("[name=%s, age=%d, hometown=%s]",this.name,this.age,this.hometown);
}
}
6、新建 HelloServiceAutoConfiguration 类
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
private final HelloProperties helloProperties;
public HelloServiceAutoConfiguration(HelloProperties helloProperties){
this.helloProperties = helloProperties;
}
@Bean
@ConditionalOnMissingBean// HelloService 类不存在时执⾏此⽅法
public HelloService helloService(){
return new HelloService(Name(),Age(),Hometown()); }
}
7、类路径下新建 META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.springboot.HelloServiceAutoConfiguration
8、modules mvn clean install ,将⼦modules打包到本地仓库
9、在⽗project中引⼊⼦ modules 的依赖
<dependencies>
<dependency>
<groupId>com.springboot</groupId>
<artifactId>hello-spring-boot-autoconfigure</artifactId>适合新手的spring boot
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
10、此时,⾃定义starter已经创建完成了,新建⼦modules ,引⼊此starter测试
11、spring-boot-test 中引⼊依赖
<!--⾃定义starter-->
<dependency>
<groupId>com.springboot</groupId>
<artifactId>hello-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
12、新建 HelloController 类
@RestController
@RequestMapping("/hello")
public class HelloController {
@Resource
private HelloService helloService;
@GetMapping("/{name}")
public String hello(@PathVariable String name){
return helloService.sayHello(name);
}
@GetMapping
public String helloWorld(){
return helloService.helloWorld();
}
}
13、application.properties 添加配置信息
my.hello.name=feiyangyang
my.hello.age=19
my.hello.hometown=bj
14、启动项⽬,测试
⾃动配置原理
springboot核⼼注解 @SpringBootApplication 是个组合注解,其中包括三个重要注解
@SpringBootConfiguration
我们可以看到,@SpringBootConfiguration 注解继承⾃ @Configuration,都⽤来声明当前类是个配置类。并且会将当前类声明的⼀个或多个以 @Bean 注解标记的实例注⼊ IOC 容器中。
并且,Spring 的配置类也是 IOC 容器的组件。
@EnableAutoConfiguration
@EnableAutoConfiguration 注解是 springboot 实现⾃动化配置的核⼼注解,就是通过这个注解把 spring 应⽤所需的 bean 注⼊到容器中。
再来看看 @AutoConfigurationPackage 注解,⾃动配置包,主要是使⽤ @Import 来给 spring 容器导⼊⼀个组件,这⾥导⼊的是AutoConfigurationPackages.Registrar.class
我们来看 AutoConfigurationPackages.Registrar.class ,发现是 AutoconfigurationPackages 类的内部类。通过分析AutoConfigurationPackages.Registrar 类的 registerBeanDefinitions ⽅法,发现其内部调⽤的 register ⽅法的参数是PackageImports 类的实例,我们来到 PackageImports 类的构造,发现此构造就是拿到所有要扫描的包路径。
我们打断点debug,发现拿到的包路径正是我们项⽬的包路径。
⽽ PackageImports 构造的参数 AnnotationMetadata 是什么东西?发现其实就是项⽬的启动类,看 PackageImports 构造发现,不过就是拿到了启动类所在的包路径,获取到了包路径,springboot 会将这个包路径下的组件扫描到 IOC 容器。
我们回到 @EnableAutoConfiguration 看看 @Import 上⾯标注的类是做什么的。
我们点到 AutoConfigurationImportSelector 类发现有⼀个 selectImports ⽅法,⽽这个⽅法做的就是将所有组件注⼊到 IOC 容器中,并且将这些组件的全限定类名返回,我们来验证⼀下。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论