SpringBoot自动装配详解---带源码
2020-05-10 04:15
1331 查看
前言
SpringBoot中我们经常直接使用
@SpringBootApplication这个复合注解去标记为配置类,包含了SpringBoot常用的三个标签
@Configuration、
@EnableAutoConfiguration、
@ComponentScan.具有这三个标签的作用声明为一个配置类、自动配置、自动扫描
使用@SpringBootApplication
注解
我们直接进入这个注解中,查看它的源码。
/** * Indicates a {@link Configuration configuration} class that declares one or more * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience * annotation that is equivalent to declaring {@code @Configuration}, * {@code @EnableAutoConfiguration} and {@code @ComponentScan}. * * @author Phillip Webb * @author Stephane Nicoll * @since 1.2.0 有道翻译: * 表示一个{@link Configuration configuration}类,该类声明一个或多个 * {@link Bean @Bean}方法,并且还触发{@link EnableAutoConfiguration * 自动配置}和{@link ComponentScan组件扫描}。这是一个方便的注释,等同于声明{@code @Configuration}, * {@code @EnableAutoConfiguration}和{@code @ComponentScan}。 */ @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 {
自动配置实现流程
1.@Import
标签
现在我们继续进入
@EnableAutoConfiguration标签里面我们可以看到,
EnableAutoConfiguration这个类,它使用了一个import导入了一个
AutoConfigurationImportSelector.calss自动导入选择器.所以我们完成自动配置的具体功能还在这里面。
@Import(AutoConfigurationImportSelector.class) <------导入选择器 public @interface EnableAutoConfiguration
@Import这个注解,能将继承了
ImportSelector这个类的子类,调用子类中的:selectImports()方法传入完全限定名,就可以将完全限定名对应的类导入SpringIOC容器中.会把第三方jar的类加载到当前spring容器
2.AutoConfigurationImportSelector
自动导入选择器
2.1继承DeferredImportSelector类
这个类的父类就继承了
ImportSelector。就刚好可以与上面的
import标签相对
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
public interface DeferredImportSelector extends ImportSelector
2.2selectImports()
方法
在
AutoConfigurationImportSelector这个类中就实现了这样一个
selectImports()这个方法(核心),可以帮助我们调用
SpringFactoriesLoader.loadFactoryNames()这个方法
//从这里可以看出该类实现很多的xxxAware和DeferredImportSelector,所有的aware都优先于selectImports //方法执行,也就是说selectImports方法最后执行,那么在它执行的时候所有需要的资源都已经获取到了 public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { ... public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { //1加载META-INF/spring-autoconfigure-metadata.properties文件 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); //2获取注解的属性及其值(PS:注解指的是@EnableAutoConfiguration注解) AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //3.在classpath下所有的META-INF/spring.factories文件中查找org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,并将其封装到一个List中返回 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //4.对上一步返回的List中的元素去重、排序 configurations = this.removeDuplicates(configurations); //5.依据第2步中获取的属性值排除一些特定的类 Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); //6对上一步中所得到的List进行过滤,过滤的依据是条件匹配。这里用到的过滤器是 //org.springframework.boot.autoconfigure.condition.OnClassCondition最终返回的是一个ConditionOutcome[] //数组。(PS:很多类都是依赖于其它的类的,当有某个类时才会装配,所以这次过滤的就是根据是否有某个 //class进而决定是否装配的。这些类所依赖的类都写在META-INF/spring-autoconfigure-metadata.properties文件里) this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return StringUtils.toStringArray(configurations); } }
2.3selectImports()
方法中list集合是整个的核心
//3.在classpath下所有的META-INF/spring.factories文件中查找org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,并将其封装到一个List中返回 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
1.在这个语句中会调用自己的一个:
SpringFactoriesLoader.loadFactoryNames()这个方法,从类路径下得到一个资源
2.在这个
SpringFactoriesLoader类中的方法中,会找到
META-INF/spring.factories这个资源文件。而这个文件中全是键值对结构
public abstract class SpringFactoriesLoader { /** * The location to look for factories. * <p>Can be present in multiple JAR files. */ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
3.那么扫描到的这些文件作用:是把这个文件的urls拿到之后并把这些urls每一个遍历,最终把这些文件整成一个properties对象。
4.最后通过开始的
import标签将spring.factories这个文件找到配置所有EnableAutoConfiguration的值加入到Spring容器中,而每一个
xxxAutoConfiguration类都是容器中的一个组件(90多个左右),并都加入到容器中。
加入到容器中之后的作用就是用它们来做自动配置,这就是Springboot自动配置之源,也就是自动配置的开始,只有这些自动配置类进入到容器中以后,接下来这个自动配置类才开始进行启动
3.自动配置生效
现在我们都能找到相应的自动配置
xxxAutoConfiguration类,然后Springboot在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:
@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。(常用)
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下(常用)
@ConditionalOnProperty:指定的属性是否有指定的值
3.1 我们以其中的RedisAutoConfiguration
类为例
@Configuration//表示这是一个配置类,类似于以前编写的配置文件一样,也可以给容器中添加组件 @ConditionalOnClass(RedisOperations.class)//根据pom里是否引入了相应的jar包,如果没有就不会启动该配置类 @EnableConfigurationProperties(RedisProperties.class)//开启配置属性,会去找相应的配置文件类,导入这个已经绑定了属性的bean到spring容器中 @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate")//会检测容器中是否有redisTemplate类的对象,如果没有则生成一个。 public RedisTemplate<Object, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean//会检测容器中是否有TestService类的对象,如果没有则生成一个。 public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
1.
@EnableConfigurationProperties(RedisProperties.class)这个注解可以找到相应的配置类,导入这个已经绑定了属性的bean到spring容器中。我们进入这个配置类中查看一些具体的信息
这里我们就截取一部分,他会自动帮我们配置一些如:端口=6379之类的信息
//这里我们就截取一部分,他会自动帮我们配置一些如:端口=6379之类的信息 @ConfigurationProperties(prefix = "spring.redis")//根据配置文件的前缀与相应的值进行绑定 public class RedisProperties { /** * Database index used by the connection factory. */ private int database = 0; /** * Connection URL. Overrides host, port, and password. User is ignored. Example: * redis://user:password@example.com:6379 */ private String url; /** * Redis server host. */ private String host = "localhost"; /** * Login password of the redis server. */ private String password; /** * Redis server port. */ private int port = 6379;
我们就可以得到一个具有一些属性的而且实例化好了的类。
4.总结
最后我们总结一下:
1.Spring Boot启动的时候会通过
@EnableAutoConfiguration注解,匹配到
@Import(AutoConfigurationImportSelector.class)
2.然后再
AutoConfigurationImportSelector.class找到
META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载
3.而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类
4.它能通过以
Properties结尾命名的类中取得在全局配置文件中配置的属性如:
server.port,而XxxxProperties类是通过
@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的 ChengHuanHuaning 原创文章 24获赞 68访问量 1万+ 关注 私信
相关文章推荐
- SpringBoot 2.2.2 源码详解(二):自动装配原理
- 详解Spring Boot自动装配的方法步骤
- SpringBoot SpringApplication底层源码分析与自动装配
- springboot2.x +redis使用和源码分析一(springboot自动装配源码分析)
- 【一文读懂】Spring Boot组件自动装配详解
- spring boot自动装配之@EnableAutoConfiguration详解
- SpringBoot自动装配源码解析
- springboot自动装配原理详解
- SpringBoot自动装配原理(1)--结合源码
- springboot2.x +kafka使用和源码分析一(自动装配)
- spring boot 源码解析40-CounterService,GaugeService默认自动装配解析
- spring boot自动装配之@ComponentScan详解
- SpringBoot自动装配流程源码分析
- SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析
- 一步步从Spring Framework装配掌握SpringBoot自动装配
- SpringBoot Profile使用详解及配置源码解析
- 深入理解SpringBoot之自动装配
- springboot自动装配原理-以redis为例
- 基于Spring Boot的Environment源码理解实现分散配置详解
- SpringBoot自动装配,实现自定义配置