SpringBoot自动装配

在没有使用SpringBoot之前,使用ssm时配置redis需要在XML中配置端口号,地址,账号密码,连接池等等,而使用了SpringBoot后只需要在application.yml或application.properties中配置信息,然后在pom文件添加一个Redis的start就可以用了

SpringBootApplication注解

什么是自动装配,也就是说帮你把需要的类自动添加到Spring容器中

只要是一个SpringBoot项目肯定有这样一个类

@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(TokenApplication.class, args);
}
}

而自动装配是在@SpringBootApplication这个注解中实现的,点进去首先能看到这个注解上还有三个类

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

其中SpringBootConfiguration上还有一个注解@Configuration也就是说明其实SpringBootApplication也是一个配置类

@ComponentScan用于扫描需要被Spring管理的类,这也就是为什么写的类需要在SpringBoot启动类同级或在同级下的子包中

@EnableAutoConfiguration点进去发现它上面有一个特殊的注解@Import(AutoConfigurationImportSelector.class)

@Import注解的作用是将指定类添加到Spring容器中成为一个Bean

而在AutoConfigurationSelector类中有自动装配的实现

	@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//下面的方法
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
} protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
//获取注解的名称作为key
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}

其中我们关注与返回值相关的代码,也就是getCandidateConfigurations这个方法

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}

继续查看loadFactoryNames方法

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
} private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
} try {
//从META-INF/spring.factories中获取配置文件
Enumeration<URL> 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()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

其中需要解释一下的是:MultiValueMap[接口],它是一个特殊的Map,由SpringBoot自己写的,查看它的实现类LinkedMultiValueMap

private final Map<K, List<V>> targetMap;

通常我们使用的Map是一个<K,V>结构的,而它这个Map是一个<K,V V V ...>结构的

首先SpringBoot会从缓存中尝试获取(其实也就是个map,不过有点特殊),如果获取不到,那就一次将全部内容读取出来,然后以K V V V...的形式存放到类中

那么META-INF/spring.factories这个文件在哪呢?

它里面的内容是这样的

以类的全限定名作为Key,其他类的全限定名作为Value

那到现在还是一头雾水,读到了这个有什么用呢?我们拿常见的Redis来看看

点进RedisAutoConfiguration看看

发现里面全是报错,因为我还没有导入Redis的start,当我在pom文件中添加redis的依赖后

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>

发现不报错了,使用RedisTemplate存取值也可以了,这里就不再演示存取值

上面这个类主要看类上面的注解,主要的两个为:ConditionalOnClassEnableConfigurationProperties

ConditionalOnClass

@ConditionalOnClass的作用是当前项目的classpath中存在某个类在会实例化这个类为bean,Spring还提供了其他类似的注解

那么毫无疑问pom中导入的那个依赖中肯定有一个类或接口叫做RedisOperations,点进去查看它的包路径

package org.springframework.data.redis.core;

我们去导入的包中找一找

EnableConfigurationProperties

@EnableConfigurationProperties注解是使@ConfigurationProperties 注解的类生效,点进注解上的类

@ConfigurationProperties注解的作用是可以将参数的配置设置在application配置文件中,我们在application配置文件中配置的参数都配置类中的字段,要不然这些参数那来的?

那么现在SpringBoot自动装配的大致流程就完成了

  1. 读取META-INF/spring.factories文件
  2. 将扫描出的类进行判断
  3. 如果符合类上的@ConditionalOnxxxx注解就将类添加到Spring容器中

如何自定义一个Start

现在知道了SpringBoot是如何自动装配的,扫描MEAT-INF下spring.factories文件,key为:EnableAutoConfiguration,为什么key为EnableAutoConfiguration呢?在上面的代码中,扫描的以@EnableAutoConfiguration注解获取名称作为key

首先创建一个Maven项目,导入依赖

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.0.RELEASE</version>
<optional>true</optional>
</dependency>
</dependencies>

之后在resources文件夹下创建META-INF/spring.factories文件

然后创建配置类 当代码没有写完时@ConfigurationProperties会报错:没有开启这个配置类,可以暂时不管

创建服务类

创建自动注入的配置类

最后在spring.factories中添加自动装配类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
\com.jame.UserServiceAutoConfiguration //这里替换成自己的类全路径

整个项目结构如下

最后将maven项目 clean install 打包到当前maven仓库中

在target输出文件夹下打开cmd 直接在路径框中输入cmd直接打开当前位置

输入命令

mvn install:install-file -Dfile=start-user-1.0-SNAPSHOT.jar -DgroupId=com.jame -DartifactId=user-spring-boot-start -Dversion=1.0 -Dpackaging=jar

  • -Dfile 文件名
  • -DgroupId 就是groupId
  • -DartifactId 项目名称,可以不和文件名一样
  • -Dversion 版本号
  • -Dpackaging打包方式

完成后新建个SpringBoot项目来测试

导入刚才打包的项目

配置参数

创建一个Controller来测试

这里使用@Autowired idea可能会提示错误,说找不到对应的类型,这个是idea的问题

如果不想看着难受可以设置:Setting->Editor->inspections->Spring Core->Core->AutoWring for bean class 将Error设置为Waring

最后访问测试:

SpringBoot自动装配-自定义Start的更多相关文章

  1. 一步步从Spring Framework装配掌握SpringBoot自动装配

    目录 Spring Framework模式注解 Spring Framework@Enable模块装配 Spring Framework条件装配 SpringBoot 自动装配 本章总结 Spring ...

  2. springboot自动装配

    Spring Boot自动配置原理 springboot自动装配 springboot配置文件 Spring Boot的出现,得益于“习惯优于配置”的理念,没有繁琐的配置.难以集成的内容(大多数流行第 ...

  3. SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  4. SpringBoot自动装配原理解析

    本文包含:SpringBoot的自动配置原理及如何自定义SpringBootStar等 我们知道,在使用SpringBoot的时候,我们只需要如下方式即可直接启动一个Web程序: @SpringBoo ...

  5. Spring Boot之从Spring Framework装配掌握SpringBoot自动装配

    Spring Framework模式注解 模式注解是一种用于声明在应用中扮演“组件”角色的注解.如 Spring Framework 中的 @Repository 标注在任何类上 ,用于扮演仓储角色的 ...

  6. springboot自动装配原理

    最近开始学习spring源码,看各种文章的时候看到了springboot自动装配实现原理.用自己的话简单概括下. 首先打开一个基本的springboot项目,点进去@SpringBootApplica ...

  7. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  8. springboot自动装配(3)---条件注解@Conditional

    之前有说到springboot自动装配的时候,都是去寻找一个XXXAutoConfiguration的配置类,然而我们的springboot的spring.factories文件中有各种组件的自动装配 ...

  9. springboot自动装配原理,写一个自己的start

    springboot自动装配原理 第一次使用springboot的时候,都感觉很神奇.只要加入一个maven的依赖,写几行配置,就能注入redisTemple,rabbitmqTemple等对象. 这 ...

随机推荐

  1. Yolov3 的 OneFlow 实现

    Yolov3 的 OneFlow 实现 1.简介 YOLO 系列的算法(经典的v1~v3),是单阶段目标检测网络的开山鼻祖,YOLO-You only look once,表明其单阶段的特征,正是由于 ...

  2. TinyML-TVM是如何驯服Tiny的(上)

    TinyML-TVM是如何驯服Tiny的(上) 低成本.人工智能驱动的消费类设备的激增,导致了ML研究人员和从业者对"裸智能"(低功耗,通常没有操作系统)设备的广泛兴趣.虽然专家已 ...

  3. NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库

    NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库 Leveraging the Hardware JPEG Decoder and NVIDIA nvJPEG Lib ...

  4. CVPR2020:点云分析中三维图形卷积网络中可变形核的学习

    CVPR2020:点云分析中三维图形卷积网络中可变形核的学习 Convolution in the Cloud: Learning Deformable Kernels in 3D Graph Con ...

  5. 从“信息化”到“智慧化”,GVS视声将如何赋能智慧医院?

    4月23日-25日,2021年中华医院信息网络大会(CHINC)盛大举办,今年首次携手中国医院建筑与装备创新发展大会,同期同地亮相杭州国际博览中心,塑造了全新的"双引擎"品牌盛会. ...

  6. JUC 并发编程--11, AQS源码原理解析, ReentrantLock 源码解读

    这里引用别人博客,不重复造轮子 https://blog.csdn.net/u012881584/article/details/105886486 https://www.cnblogs.com/w ...

  7. centos7 安装 bbr加速

    脚本安装 1 查看内核版本 # [root@os]# uname -a Linux os 3.10.0-1127.13.1.el7.x86_64 x86_64 x86_64 x86_64 GNU/Li ...

  8. 【NX二次开发】Block UI 角度尺寸

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  9. 使用Flutter设计一个好看的"我"页面

    近期遇到一些很烦的琐事,状态比较down,很多原本计划好的事情都耽搁了,实在是难顶-- 看到后台一直有朋友问怎么博客和公众号没有更新,所以我忙完得闲就来更了! 前言 起因是最近重拾以前的旧项目(业余做 ...

  10. 「10.8」simple「数学」·walk「树上直径」

    A. Simple 本来以为很难,考场瞎推了推好像会了...... 想起小凯的诱惑,迷?? 首先$n$,$m$,$q$同除$gcd(n,m)$,显然$q$以内的数假如不是$gcd$的倍数,那么一定不能 ...