SpringBoot源码分析(二)之自动装配demo

文章目录

  • SpringBoot源码分析(二)之自动装配demo
  • 前言
  • 一、创建RedissonTemplate的Maven服务
  • 二、创建测试服务
  • 三、总结

前言

Spring Framework一致在解决如何让bean的管理更加简单,如何让开发者尽可能少的去管理bean生成的一些配置;当我们在引用其他模块中的bean时,我们可以自动的创建bean,并交给spring的Ioc容器去管理。
spring3.x产生了Enable模块驱动注解,在调用其他模块bean的时候,可以通过Enable注解或者import注解生成bean。但是在spring4.x中,conditional条件注解的出现才真正的实现了自动装配。
在阅读自动装配源码之前,我们先来演示一个自动装配的案例。本文讲解的是如何定义一个有条件的Redis自动装配的模板。

一、创建RedissonTemplate的Maven服务

Maven项目版本:

<groupId>com.my</groupId>
<artifactId>RedissonTemplate</artifactId>
<version>1.0-SNAPSHOT</version>

创建带有@Configuration注解的RedissonAutoConfiguration.class:

package com.my.redission;import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
//@ConditionalOnClass(RedissonProperties.class)
public class RedissonAutoConfiguration {/*** RedissonClient:操作Redis的核心对象*     将该对象注入到容器中*     需要连接Redis 服务, host  port* @return*/@Beanpublic RedissonClient redissonClient(RedissonProperties redissonProperties){Config config = new Config();String prefix = "redis://";if(redissonProperties.getSsl()){prefix = "rediss://";}config.useSingleServer().setAddress(prefix+redissonProperties.getHost()+":"+redissonProperties.getPort()).setTimeout(redissonProperties.getTimeout());return Redisson.create(config);}}

我们可以看到改类上携带了EnableConfigurationProperties(RedissonProperties.class)注解,该注解是自动从application.yml/application.properties文件中获取关于Redis的有关配置参数。
RedissonProperties.clas

package com.my.redission;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@Data
@ConfigurationProperties(prefix = "my.redisson")
public class RedissonProperties {private String host = "localhost";private Integer port = 6379;private Integer timeout = 1000;private Boolean ssl = false;}

此处使用了lombok.Data注解,就不需要我们对RedissonProperties的成员变量进行get、set处理了。但是别忘记了需要添加lombok.Data的依赖。

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency>

此刻,我们完成了程序的编写,接下来,我们会配置我们服务的自动装配。
我们需要在resource下创建一个META-INF文件夹,在META-INF文件夹下添加三个文件,分别是:spring.factories、additional-spring-configuration-metadata.json和spring-autoconfigure-metadata.properties。

首先,我们先讲一下additional-spring-configuration-metadata.json,该文件是为了配置如何从application.yml/application.properties文件中获取RedissonProperties中的成员变量的信息,也就是Redis的配置参数。
additional-spring-configuration-metadata.json

{"properties": [{"name": "my.redisson.host","type": "java.lang.String","description": "Redis的服务地址","defaultValue": "localhost"},{"name": "my.redisson.port","type": "java.lang.Integer","description": "Redis的服务端口","defaultValue": 6379},{"name": "my.redisson.timeout","type": "java.lang.Integer","description": "Redis的服务端口","defaultValue": 1000},{"name": "my.redisson.ssl","type": "java.lang.Boolean","description": "Redis的服务端口","defaultValue": false}]
}

spring.factories文件中配置了RedissonAutoConfiguration类的全路径,可以让Spring Boot通过自动装配加载RedissonAutoConfiguration类。加载的原理是通过SpringFactoriesLoader从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。该文件中的数据格式:key为自定配置类EnableAutoConfiguration的全路径,value是配置类的全路径;其中EnableAutoConfiguration就是自动装配的Enable。
spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.my.redission.RedissonAutoConfiguration

Spring Boot的自动装配中可以使用条件过滤,即conditional。
AutoConfigurationImportSelector方法会先扫描spring-autoconfiguration-metadata.properties文件,获取需要装配的类;最后再扫描spring.factories对应的类时,会结合前面的元数据进行过滤。为什么自动装配需要有过滤的条件,因为@Configuration注释的bean大部分情况下,需要依赖其他框架的类,当依赖的类不存在时,就不能将该bean注入到Ioc。同时也可以减少无效的@configuration类的数量从而降低SpringBoot的启动时间。Spring Boot同时也将自己的二方依赖框架和友商的依赖框架的@Configuration的类全路径添加在spring-boot、spring-boot-autoconfigure框架下的classpath/META-INF/spring.factories文件中,当条件满足的时候,会自动加载spring.factories文件中的bean。
就像本文的demo,RedissonTemplate在创建RedissonAutoConfiguration类时,需要依赖org.redisson.api.RedissonClient类。那么我们就可以将这个条件加上,只有当项目的classpath中有org.redisson.api.RedissonClient类时,Spring Boot的自动装配才能将RedissonAutoConfiguration加载到Ioc中。
spring-autoconfigure-metadata.properties

com.my.redission.RedissonAutoConfiguration=
com.my.redission.RedissonAutoConfiguration.ConditionalOnClass=org.redisson.api.RedissonClient

ConditionalOnClass的意思就是后面的类需要存在,同时Conditional条件注解还有很多。像:ConditionalOnBean、ConditionalOnResource等。

如果我们不使用spring-autoconfigure-metadata.properties文件配置,也可以在RedissonAutoConfiguration类上添加@ConditionalOnClass(RedissonProperties.class)注解。

至此,我们的RedissonTemplate配置完成。

二、创建测试服务

首先我们先创建一个spring boot项目,将RedissonTemplate的依赖引入。

<dependency><groupId>com.my</groupId><artifactId>RedissonTemplate</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

然后在application.yml/application.properties文件中配置Redis的启动参数:

my:redisson:host: 127.0.0.1port: 6379timeout: 2000

编写测试案例,我们通过Controller对外提供一个get接口,在浏览器中通过访问get接口来访问Redis中的数据,如果能正常连接到Redis并正常访问Redis数据,及代表,RedissonTemplate被自动装配到Ioc中。
首先,我们先排除@ComponentScan注解的自动扫描。由图可以看出,我们没有配置@ComponentScan扫描路径,所以该路径为当前class路径及其子类。

我们的启动类的全路径:com.example.demo1.Demo1Application
我们的RedissonTemplate的全路径:com.my.redission.RedissonAutoConfiguration

编写我们的Controller层代码:

package com.example.demo1.action;import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api")
public class RedissionAction {@Autowiredprivate RedissonClient redissonClient;@GetMapping("/query")public String query(){return "key的个数="+redissonClient.getKeys().count()+"";}
}

由1中可以得知,自动装配RedissonTemplate的条件是

我们看一下我们的libraries中是否存在org.redission框架,以及该框架中是否存在RedisClient。


可以看出,我们的条件满足自动装配RedissonTemplate。接下来,我们运行Spring Boot测试项目。可以看到启动日志中打印出连接上Redis的日志信息。

同时,我们来访问我们的controller接口,可以看到返回了redis中的key的数量。

接下来,我们测试一下条件不符合的场景。
我们将spring-autoconfigure-metadata.properties文件的条件改成:项目中必须存在rg.redisson.api.RedissonClientTets类,当然了该类是不存在的。

com.my.redission.RedissonAutoConfiguration=
com.my.redission.RedissonAutoConfiguration.ConditionalOnClass=org.redisson.api.RedissonClientTets

此时,我们再运行测试项目,将会看到Spring Boot启动报错,显示Field redissonClient in com.example.demo1.action.RedissionAction required a bean of type ‘org.redisson.api.RedissonClient’ that could not be found.
意思就是找不到RedissonClient这个Bean。

三、总结

至此,我们完成了如何配置一个自动装配的工程。下一章节,我们将从源码的角度去解读自动装配的逻辑。

SpringBoot源码分析(二)之自动装配demo相关推荐

  1. Springboot源码分析第一弹 - 自动装配实现

    Springboot就不用多了吧,解放Java开发双手的神器. 最显著的特点就是,去配置化,自动装配,自动配置.让开发人员只需要注重业务的开发 今天就来了解一下自动装配的源码是怎么实现的 预先准备 直 ...

  2. SpringBoot源码分析之内置Servlet容器

    原文链接:http://fangjian0423.github.io/2017/05/22/springboot-embedded-servlet-container/ SpringBoot内置了Se ...

  3. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  4. gSOAP 源码分析(二)

    gSOAP 源码分析(二) 2012-5-24 flyfish 一 gSOAP XML介绍 Xml的全称是EXtensible Markup Language.可扩展标记语言.仅仅是一个纯文本.适合用 ...

  5. Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现

    写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...

  6. 【投屏】Scrcpy源码分析二(Client篇-连接阶段)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  7. Nouveau源码分析(二):Nouveau结构体的基本框架

    Nouveau源码分析(二) 在讨论Nouveau对Nvidia设备的初始化前,我准备先说一下Nouveau结构体的基本框架 Nouveau的很多结构体都可以看作是C++中的类,之间有很多相似的东西, ...

  8. ENS最新合约源码分析二

    ENS(以太坊域名服务)智能合约源码分析二 0.简介 ​ 本次分享直接使用线上实际注册流程来分析最新注册以太坊域名的相关代码.本次主要分析最新的关于普通域名注册合约和普通域名迁移合约,短域名竞拍合约不 ...

  9. springboot源码(二)@SpringBootApplication注解中exclude参数使用及原理

    文章目录 一.使用姿势 二.运行原理 上篇文章中, <springboot源码(一)启动流程+自动配置原理分析>,简单分析了启动流程,其中涉及到了@SpringBootApplicatio ...

最新文章

  1. 从java到c_Binder机制,从Java到C (4. Parcel)
  2. php获取表单信息的代码_php 表单数据的获取代码
  3. 《长安十二时辰》中的跨域行人重识别问题
  4. 三个已存在15年的 Linux 内核漏洞
  5. 用FileZilla创建的Ftp如何使用匿名登录
  6. 在命令行中使用ssh连接远程服务器
  7. ubuntu etc文件夹在哪_嵌入式Linux开发学习之 Ubuntu 和 Windows 文件互传
  8. Mybatis笔记(狂神)
  9. 点击电脑桌面图标就点计算机图标老是出现是否删除快捷方式,电脑点击桌面图标提示缺少快捷方式怎么办...
  10. 保温杯内壁有很多小泡泡
  11. tensorboard--曲线图颜色深浅两条线
  12. python科学计算环境配置_ATLAS + NumPy + SciPy + Theano 的Python科学计算环境搭建
  13. 让我们跳过中年危机,直接聊聊如何善终
  14. 第十三章 Java 文件与流
  15. MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数
  16. 反向跟单为什么盈利率那么高
  17. 基于SphereFace深度学习的人脸考勤系统(Caffe+windows+OpenCV)
  18. react 中 JSX 语法的转化过程
  19. KITTI 3D目标检测数据集入门
  20. Spring 常用注解 脑图版

热门文章

  1. lisp边长注记_小程序cad批量注记建筑物边长
  2. CSDN:2019年度CSDN博客之星评选竞赛——105号【一个处女座的程序猿】,感谢您,投上的宝贵一票,感谢!感恩!
  3. 用python写一个PDF翻译软件
  4. Hark的数据结构与算法练习之计数排序
  5. Android手机下载的缓存视频如何找到?
  6. linux 光标切换快捷键,光标操作快捷键,光标快捷键
  7. c语言滤出是个最小值,经典滤波算法及C语言程序
  8. 如何用Word编辑参考文献(转)
  9. 华为交换机配置时区_华为交换机配置命令
  10. jones 的 C语言复习