什么是自动装配
通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。
spring 是如何实现自动装配的?
springboot 的自动配置是基于 spring factories 机制实现的,这是一种服务发现机制,类似 Java SPI。 spring 会自动扫描所有 jar 包类路径下的 META-INF/spring.factories 文件,读取其中的类型并进项实例化。spring.factories 文件中的内容实际上就是要导入的接口名和实现类组成的 kv 对,key 为文件中定义的一些标识工厂类,value 就是能自动配置的一些工厂实现的类。 在自动装配时,其实就是去加载 AutoConfiguration 类和实现类,在加载自动配置类的时候,并不是将 spring.factories 的配置全部加载进来,而是通过 @Conditional 等注解的判断进行动态加载,只有当容器满足了注解中的条件的时候,才会将类加载到容器中
偷来的八股文:自动装配依托 @Import 的强大功能和 spring 的 SPI 机制。通过 SPI 机制发现类,通过 @Import 将类注册到 spring 中。@SpringBootApplication 这个注解时组合注解里面包含自动扫描注解,里面包含一个 EnableAutoConfiguration 注解,这个注解作用是去寻找每个 jar 包里面的 META-INF/spring.factories 文件,之后将文件里面的类全部实例化。每个需要自动装配的模块都需要编写一个 AutoConfiguration 类,这些 AutoConfiguration 类的原理大概是通过 @Import 注解将其属性类 Properties 全部到注册 spring 容器中,属性类通过注解 @ConfigurationProperties 从配置文件里面取到配置值。之后将关键的类注册为 bean 自动注入属性类进行初始化完成自动装配的功能。
细分相关知识如下:
我们知道
@SpringBootApplication = @SpringBootConfiguration+@EnableAutoConfiguration+@ComponentScan
复制代码
我们要重点关注这个 @EnableAutoConfiguration.看到 EnableAutoConfiguration.class 文件有个 @Import({AutoConfigurationImportSelector.class})
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
复制代码
流程图
第一步会去看这个
可以看到默认是 spring.boot.enableautoconfiguration 的值默认是 true。
得到排除的依赖项
得到配置内容
如何自己实现一个 starter?
在 resources/META-INF 中新建 spring.factories 文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.roger.demospringbootstarter.config.DemoConfig
复制代码
在这个 EnableAutoConfiguration 的属性所对应的 java 文件中写入自己想装配的 bean.
/**
* @author: 骆佳俊
* @date: 2022/4/27 10:21 AM
*/
@Configuration
public class DemoConfig {
private static final Logger logger = LoggerFactory.getLogger(DemoConfig.class);
@Bean
public void demoService() {
logger.info("我是自动装配进来的");
}
}
复制代码
在外部如何引用?本地打包的时候可以直接点击 mvn clean pakcage.然后会在本地的 maven 仓库中出现该 jar 文件。
<dependency>
<groupId>com.roger</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
复制代码
如何自动配置是否生效
启动的时候可以增加-Ddebug 参数.会有以下 4 种形式的输出
Unconditional classes:
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
com.roger.demospringbootstarter.config.DemoConfig
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
复制代码
最终在输出的命令行中我看见了 com.roger.demospringbootstarter.config.DemoConfig 该 Bean.
最后的效果
2022-04-30 10:57:06.150 INFO 56979 --- [ main] r.c.j.JavaFundamentApplication : Starting JavaFundamentApplication using Java 1.8.0_312 on YolandadeMacBook-Air.local with PID 56979 (/Users/yolanda/code/javaProject/javaFundament/target/classes started by yolanda in /Users/yolanda/code/javaProject/javaFundament)
2022-04-30 10:57:06.152 INFO 56979 --- [ main] r.c.j.JavaFundamentApplication : No active profile set, falling back to 1 default profile: "default"
2022-04-30 10:57:09.567 INFO 56979 --- [ main] c.r.d.config.DemoConfig : 我是自动装配进来的
asdas dlksa dsj kldsja kldsaj klasjdl ksaj
2022-04-30 10:57:09.656 INFO 56979 --- [ main] r.c.j.JavaFundamentApplication : Started JavaFundamentApplication in 3.71 seconds (JVM running for 4.835)
Disconnected from the target VM, address: '127.0.0.1:61225', transport: 'socket'
复制代码
源代码自取
https://github.com/ZuccRoger/AutoConfigaration
参考资料
Javaguide
极客时间-了解自动装配实现原理
评论