栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot 自动装配原理解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot 自动装配原理解析

自动装配是 Spring Boot 的核心部分,也是 Spring Boot 功能的基础,正是由于自动装配,才 将我们从 Bean 的繁复配置中解脱出来。那么 Spring Boot 中的自动装配指的是什么?我们继 续以 Spring MVC 为例,不使用 Spring Boot 时,我们可能需要配置视图解析器,文件解析器, 请求适配器等等各种 Bean,如果在使用数据库,redis,还需要配置数据库、redis 相关 Bean。

1、从@SpringBoot Application(啊不雷可雷神) 启动注 解入手

@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 {
 @AliasFor(annotation = EnableAutoConfiguration.class)
 Class[] exclude() default {};
 @AliasFor(annotation = EnableAutoConfiguration.class)
 String[] excludeName() default {};
//根据包路径扫描
 @AliasFor(annotation = ComponentScan.class, attribute =
"basePackages")
 String[] scanbasePackages() default {};
//直接根据 class 类扫描
 @AliasFor(annotation = ComponentScan.class, attribute =
"basePackageClasses")
 Class[] scanbasePackageClasses() default {};
}
初看@SpringBootApplication 有很多的注解组成,其实归纳就是一个"三体"结
构,重要的只有三个 Annotation:

@Configuration(康飞的累神)(@SpringBootConfiguration 实质就是一个@Configuration)

@EnableAutoConfiguration(昂买的度 康飞的累神)

@ComponentScan(康抛闹的死改)

 也就是说我们在开发的时候,加上上面的上个注解会等同于加上
@SpringBootApplication 注解
(1)@Configuration 注解

 这个注解实际上就是代表了一个配置类,相当于一个 beans.xml 文件
(2)@ComponentScan(康抛闹的死改)

 @ComponentScan 的功能其实就是自动扫描并加载符合条件的组件或 bean
定义,最终将这些 bean 定义加载到容器中
(3)@EnableAutoConfiguration(昂买的度 康飞的累神)

 在 spring 中有关于@Enablexxx 的注解是开启某一项功能的注解,比如
@EnableScheduling 表示开启 spring 的定时任务。其原理是借助@import(in抛的)
的帮助,将所有符合自动配置条件的 bean 定义加载到 Ioc 容器。
 EnableAutoConfiguration 代表开启 springboot 的自动装配

源码

@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 {};
}
从源码中可以知道,最关键的要属
@import(EnableAutoConfigurationimportSelector.class),借助
EnableAutoConfigurationimportSelector(昂买的度 康飞的累神 in抛可来的),@EnableAutoConfiguration(昂买的度 康飞的累神) 可以帮
助 SpringBoot 应用将所有符合条件的@Configuration(康飞的累神) 配置都加载到当前
SpringBoot 创建并使用的 IoC 容器。同时借助于 Spring 框架原有的一个工具类:
SpringFactoriesLoader(s斌坏的瑞猫都),@EnableAutoConfiguration 

(昂买的度 康飞的累神)就可以实现智能的自动配
置。
//从这里可以看出该类实现很多的 xxxAware 和 DeferredimportSelector,所有
的 aware 都优先于 selectimports(s来的抛人的)
//方法执行,也就是说 selectimports 方法最后执行,那么在它执行的时候所有
需要的资源都已经获取到了

AutoConfigurationimportSelector(奥都 康非的累神 in抛的 s来挺)源码

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 configurations =
this.getCandidateConfigurations(annotationmetadata, attributes);
//4.对上一步返回的 List 中的元素去重、排序
 configurations = this.removeDuplicates(configurations);
//5.依据第 2 步中获取的属性值排除一些特定的类
 Set exclusions =
this.getExclusions(annotationmetadata, attributes);
//6 对上一步中所得到的 List 进行过滤,过滤的依据是条件匹配。这里用到的
过滤器是
//org.springframework.boot.autoconfigure.condition.OnClassCondition
最终返回的是一个 ConditionOutcome[](k的死out 上)
//数组。(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);
 }
 }
 protected List getCandidateConfigurations(Annotationmetadata 
metadata, AnnotationAttributes attributes) {
 List configurations =
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderF
actoryClass(), this.getBeanClassLoader());
 Assert.notEmpty(configurations, "No auto configuration classes 
found in meta-INF/spring.factories. If you are using a custom packaging, 
make sure that file is correct.");
 return configurations;
 }

}

SpringFactoriesLoader(spring坏的瑞猫都) 中加载配置,SpringFactoriesLoader 属于 Spring 框架私有的一种扩展方案,其主要功能就是从指定的配置文件 meta-INF/spring.factories(坏的瑞死) 加载配置,即根据 @EnableAutoConfiguration(昂买的度 康飞的累神) 的完整类名 org.springframework.boot.autoconfigure.EnableAutoConfiguration 作为查找的 Key,获取对应的一组@Configuration(康飞的累神) 类

SpringFactoriesLoader(spring坏的瑞猫都)源码

public abstract class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION =
"meta-INF/spring.factories";
private static Map> loadSpringFactories(@Nullable
ClassLoader classLoader) {
 MultiValueMap result = cache.get(classLoader);
 if (result != null)
 return result;
 try {
 Enumeration urls = (classLoader != null ?
 
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
 
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
 result = new linkedMultiValueMap<>();
 while (urls.hasMoreElements()) {
 URL url = urls.nextElement();
 UrlResource resource = new UrlResource(url);
 Properties properties =
PropertiesLoaderUtils.loadProperties(resource);
 for (Map.Entry entry : properties.entrySet()) {
 List factoryClassNames = Arrays.asList(
 
StringUtils.commaDelimitedListToStringArray((String)
entry.getValue()));
 result.addAll((String) entry.getKey(),
factoryClassNames);
 }
 }
 cache.put(classLoader, result);
 return result;
 }
 catch (IOException ex) {
 throw new IllegalArgumentException("Unable to load 
factories from location [" +
 FACTORIES_RESOURCE_LOCATION + "]", ex);
 }
 }

@EnableAutoConfiguration(昂买的度 康飞的累神) 作用就是从 classpath 中搜寻所有的 meta-INF/spring.factories(坏的瑞死) 配置文件,并将其中 org.springframework.boot.autoconfigure.EnableutoConfiguration 对应的 配置项通过反射(Java Refletion)实例化为对应的标注了@Configuration 的 JavaConfig(康非的) 形式的 IoC 容器配置类,然后汇总为一个并加载到 IoC 容器。这些 功能配置类要生效的话,会去 classpath 中找是否有该类的依赖类(也就是 pom.xml 必须有对应功能的 jar 包才行)并且配置类里面注入了默认属性值类, 功能类可以引用并赋默认值。生成功能类的原则是自定义优先,没有自定义时才 会使用自动装配类。

所以功能类能生效需要的条件:

(1)spring.factories 里面有这个类的 配置类(一个配置类可以创建多个围绕该功能的依赖类)

(2)pom.xml 里面需要有对应的 jar 包

自动装配案例说明以 Redis 为例

从 spring-boot-autoconfigure.jar/meta-INF/spring.factories 中获取
redis 的相关配置类全限定名(有 120 多个的配置类)RedisAutoConfiguration,
一般一个功能配置类围绕该功能,负责管理创建多个相关的功能类,比如
RedisAutoConfiguration 负责:JedisConnectionFactory、RedisTemplate、
StringRedisTemplate 这 3 个功能类的创建
spring.factories 中的 redis 配置类
2、RedisAutoConfiguration 配置类生效的一个条件是在 classpath 路径下有
RedisOperations 类存在,因此 springboot 的自动装配机制会会去 classpath
下去查找对应的 class 文件。
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@import({ LettuceConnectionConfiguration.class,
JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {


}
3.如果 pom.xml 有对应的 jar 包,就能匹配到对应依赖 class,

 org.springframework.boot
 spring-boot-starter-data-redis
 

 
 4、匹配成功,这个功能配置类才会生效,同时会注入默认的属性配置类
@EnableConfigurationProperties(RedisProperties.class)
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
 private int database = 0;
 private String url;
 private String host = "localhost";
 private String password;
 private int port = 6379;
 5.Redis 功能配置里面会根据条件生成最终的 JedisConnectionFactory、
RedisTemplate,并提供了默认的配置形式@ConditionalOnMissingBean(name = 
"redisTemplate")
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@import({ LettuceConnectionConfiguration.class,
JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
 @Bean
//用户没定义就使用默认的
 @ConditionalOnMissingBean(name = "redisTemplate")
 public RedisTemplate redisTemplate(
 RedisConnectionFactory redisConnectionFactory) throws 
UnknownHostException {
 RedisTemplate template = new RedisTemplate<>();
 template.setConnectionFactory(redisConnectionFactory);
 return template;
 }
 @Bean
 @ConditionalOnMissingBean(StringRedisTemplate.class)
 public StringRedisTemplate stringRedisTemplate(
 RedisConnectionFactory redisConnectionFactory) throws 
UnknownHostException {
 StringRedisTemplate template = new StringRedisTemplate();
 template.setConnectionFactory(redisConnectionFactory);
 return template;
 }
}

6.最终创建好的默认装配类,会通过功能配置类里面的 @Bean 注解,注入到 IOC
当中
7.用户使用,当用户在配置文件中自定义时候就会覆盖默认的配置
@ConditionalOnMissingBean(name = "redisTemplate")

自动依赖过程总结

1.通过各种注解实现了类与类之间的依赖关系,容器在启动的时候 Application(啊不瑞k神).run,会调用 EnableAutoConfigurationimportSelector((昂买的度 康飞的累神 in抛可来的)).class 的 selectimports(s来的抛人的) 方法(其实是其父类的方法)--这里需要注意,调用这个方法之 前发生了什么和是在哪里调用这个方法需要进一步的探讨

2.selectimports (s来的抛人的)方法最终会调用 SpringFactoriesLoader(spring坏的瑞猫都).loadFactoryNames(奥楼 坏的瑞) 方法来获取一个全面的常用 BeanConfiguration 列表

3.loadFactoryNames(奥楼 坏的瑞) 方法会读取 FACTORIES_RESOURCE_LOCATION(也就是 spring-boot-autoconfigure.jar 下面的 spring.factories),获取到所有的 Spring 相关的 Bean 的全限定名 ClassName,大概 120 多个

4.selectimports(s来的抛人的) 方法继续调用 filter(飞有的)(configurations, autoConfigurationmetadata);这个时候会根据这些 BeanConfiguration 里面的 条件,来一一筛选,最关键的是 @ConditionalOnClass(k的醒热康的坏死),这个条件注解会去 classpath 下查找,jar 包里面是否 有这个条件依赖类,所以必须有了相应的 jar 包,才有这些依赖类,才会生成 IOC 环境需要的一些默认配置 Bean

5.最后把符合条件的 BeanConfiguration 注入默认的 EnableConfigurationPropertie(in的博客 飞的雷神 抛的in) 类里面的属性值,并且注入到 IOC 环境当使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录
  • 前言
  • 一、pandas是什么?
  • 二、使用步骤
    • 1.引入库
    • 2.读入数据
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、pandas是什么?

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

二、使用步骤 1.引入库

代码如下(示例):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import  ssl
ssl._create_default_https_context = ssl._create_unverified_context
2.读入数据

代码如下(示例):

data = pd.read_csv(
    'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())

该处使用的url网络请求的数据。


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
`

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/292478.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号