帮企业建设网站和推广网站,网站里添加百度地图,vi品牌形象设计案例,网创什么是 SpringBoot 自动装配#xff1f;
我们现在提到自动装配的时候#xff0c;一般会和 Spring Boot 联系在一起。但是#xff0c;实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上#xff0c;通过 SPI 的方式#xff0c;做了进一步优化。 Spr…什么是 SpringBoot 自动装配
我们现在提到自动装配的时候一般会和 Spring Boot 联系在一起。但是实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上通过 SPI 的方式做了进一步优化。 SpringBoot 定义了一套接口规范这套规范规定SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件将文件中配置的类型信息加载到 Spring 容器此处涉及到 JVM 类加载机制与 Spring 的容器知识并执行类中定义的各种操作。对于外部 jar 来说只需要按照 SpringBoot 定义的标准就能将自己的功能装置进 SpringBoot。 没有 Spring Boot 的情况下如果我们需要引入第三方依赖需要手动配置非常麻烦。但是Spring Boot 中我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话直接在项目中引入对应的 starter 即可。
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
引入 starter 之后我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。在我看来自动装配可以简单理解为通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。
SpringBoot 是如何实现自动装配的
我们先看一下 SpringBoot 的核心注解 SpringBootApplication 。
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
1.SpringBootConfiguration
2.ComponentScan
3.EnableAutoConfiguration
public interface SpringBootApplication {}Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Configuration //实际上它也是一个配置类
public interface SpringBootConfiguration {
}
大概可以把 SpringBootApplication看作是 Configuration、EnableAutoConfiguration、ComponentScan 注解的集合。根据 SpringBoot 官网这三个注解的作用分别是
EnableAutoConfiguration启用 SpringBoot 的自动配置机制Configuration允许在上下文中注册额外的 bean 或导入其他配置类ComponentScan扫描被Component (Service,Controller)注解的 bean注解默认会扫描启动类所在的包下所有的类 可以自定义不扫描某些 bean。如下图所示容器中将排除TypeExcludeFilter和AutoConfigurationExcludeFilter。 EnableAutoConfiguration 是实现自动装配的重要注解我们以这个注解入手。
EnableAutoConfiguration:实现自动装配的核心注解
EnableAutoConfiguration 只是一个简单地注解自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector类。
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
AutoConfigurationPackage //作用将main包下的所有组件注册到容器中
Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration;Class?[] exclude() default {};String[] excludeName() default {};
}
我们现在重点分析下AutoConfigurationImportSelector 类到底做了什么
AutoConfigurationImportSelector:加载自动装配类
AutoConfigurationImportSelector类的继承体系如下
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}public interface DeferredImportSelector extends ImportSelector {}public interface ImportSelector {String[] selectImports(AnnotationMetadata var1);
}
可以看出AutoConfigurationImportSelector 类实现了 ImportSelector接口也就实现了这个接口中的 selectImports方法该方法主要用于获取所有符合条件的类的全限定类名这些类需要被加载到 IoC 容器中。
private static final String[] NO_IMPORTS new String[0];public String[] selectImports(AnnotationMetadata annotationMetadata) {// 1.判断自动装配开关是否打开if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {//2.获取所有需要装配的beanAutoConfigurationMetadata autoConfigurationMetadata AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}}
这里我们需要重点关注一下getAutoConfigurationEntry()方法这个方法主要负责加载自动配置类的。
该方法调用链如下 现在我们结合getAutoConfigurationEntry()的源码来详细分析一下
private static final AutoConfigurationEntry EMPTY_ENTRY new AutoConfigurationEntry();AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {//1.if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {//2.AnnotationAttributes attributes this.getAttributes(annotationMetadata);//3.ListString configurations this.getCandidateConfigurations(annotationMetadata, attributes);//4.configurations this.removeDuplicates(configurations);SetString exclusions this.getExclusions(annotationMetadata, attributes);this.checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);configurations this.filter(configurations, autoConfigurationMetadata);this.fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);}}
第 1 步:
判断自动装配开关是否打开。默认spring.boot.enableautoconfigurationtrue可在 application.properties 或 application.yml 中设置 第 2 步
用于获取EnableAutoConfiguration注解中的 exclude 和 excludeName。 第 3 步
获取需要自动装配的所有配置类读取META-INF/spring.factories
spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories 从下图可以看到这个文件的配置内容都被我们读取到了。XXXAutoConfiguration的作用就是按需加载组件。 不光是这个依赖下的META-INF/spring.factories被读取到所有 Spring Boot Starter 下的META-INF/spring.factories都会被读取到。
所以你可以清楚滴看到 druid 数据库连接池的 Spring Boot Starter 就创建了META-INF/spring.factories文件。
如果我们自己要创建一个 Spring Boot Starter这一步是必不可少的。 第 4 步
到这里可能面试官会问你:“spring.factories中这么多配置每次启动都要全部加载么”。很明显这是不现实的。我们 debug 到后面你会发现configurations 的值变小了。
因为这一步有经历了一遍筛选ConditionalOnXXX 中的所有条件都满足该类才会生效。
Configuration
// 检查相关的类RabbitTemplate 和 Channel是否存在
// 存在才会加载
ConditionalOnClass({ RabbitTemplate.class, Channel.class })
EnableConfigurationProperties(RabbitProperties.class)
Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
}
有兴趣的童鞋可以详细了解下 Spring Boot 提供的条件注解
ConditionalOnBean当容器里有指定 Bean 的条件下ConditionalOnMissingBean当容器里没有指定 Bean 的情况下ConditionalOnSingleCandidate当指定 Bean 在容器中只有一个或者虽然有多个但是指定首选 BeanConditionalOnClass当类路径下有指定类的条件下ConditionalOnMissingClass当类路径下没有指定类的条件下ConditionalOnProperty指定的属性是否有指定的值ConditionalOnResource类路径是否有指定的值ConditionalOnExpression基于 SpEL 表达式作为判断条件ConditionalOnJava基于 Java 版本作为判断条件ConditionalOnJndi在 JNDI 存在的条件下差在指定的位置ConditionalOnNotWebApplication当前项目不是 Web 项目的条件下ConditionalOnWebApplication当前项目是 Web 项 目的条件下#
如何实现一个 Starter
现在就来撸一个 starter实现自定义线程池
第一步创建threadpool-spring-boot-starter工程 第二步引入 Spring Boot 相关依赖 第三步创建ThreadPoolAutoConfiguration 第四步在threadpool-spring-boot-starter工程的 resources 包下创建META-INF/spring.factories文件
最后新建工程引入threadpool-spring-boot-starter 测试通过 总结
Spring Boot 通过EnableAutoConfiguration开启自动装配通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配自动配置类其实就是通过Conditional按需加载的配置类想要其生效必须引入spring-boot-starter-xxx包实现起步依赖