IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【SpringBoot自动装配原理(一)】 -> 正文阅读

[Java知识库]【SpringBoot自动装配原理(一)】

注意: 本文只是简单阐述,自己动手来感受springboot对核心对象创建的控制,更详细的原理请关注后续文章

1. 前言

在springBoot中,相比于spring来说,它有一个核心的特点就是能够实现自动装配,自动装配是如何实现的?比如说当用户导入了一个redis的启动器,为什么springboot就会自动创建RedisTemplate对象,如果不导入为什么就不会创建呢?也就是类似于我添加了某些依赖就会自动创建某些对象,不添加就不会创建。

2.模拟实现简易版自动装配

  • 需求:当我添加了Redis的依赖就自动创建Person实体类对象,如果没有添加Redis依赖就不创建。(模拟springboot添加依赖就会自动创建某些对象)
  • 涉及注解
    • @Configuration 注解:放在某个配置类上,告诉spring该类为一个配置类,作用类似于xml配置文件。
    • @Bean 注解 : 放在某个方法之上,将方法的返回值注入到spring容器中,而被注入到spring容器中的对象名字默认是方法名,一般配合@Configuration注解一起使用。
    • (核心) @Conditional 注解:传入参数为一个实现了Condition接口的类的.class,而实现Condition接口的话,实现类中就必须重写Condition接口中的matches()方法,该方法返回值为boolean,如果为true则表示@Conditional注解中的条件为true,此时该Bean会被创建,如果为false,则该Bean不会被创建。
      概括来说:就是根据条件选择性的决定某个Bean是否被创建。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
 //参数是一个实现/继承了Condition接口的类的.class
    Class<? extends Condition>[] value();
}
@FunctionalInterface
public interface Condition {
	//返回值为boolean,如果为true则表示@Conditional注解中的条件为true,否则为false
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
  • 实现步骤:
  1. 编写一个类去实现/继承Condition接口,并且重写matches方法
public class DecideConfig implements Condition{
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        boolean flag = true;
        try {
        //如果添加了Redis依赖,则springboot会自动创建RedisTemplate对象,否则不会
            Class<?> name = Class.forName("org.springframework.data.redis.core.RedisTemplate");
        } catch (ClassNotFoundException e) {
        //程序到这里,表示没有找到RedisTemplate类,也就是没有添加Redis依赖
            e.printStackTrace();
            flag = false; 
        }
        return flag;
    }
}

  1. 创建一个PersonConfig配置类,里面根据条件来决定是否要创建Person对象
@Configuration  //表示该类是一个配置类,spring容器启动会读取该类
public class RedisConfig {
    //需求:如果加了redis的依赖就创建Person对象,否则不创建
    @Bean
    //这里根据DecideConfig.class的matches()返回一个true或者false,决定Person对象是否创建
    @Conditional(DecideConfig.class)
    public Person person(){
        return new Person();
    }
}
  1. 创建测试类来测试
@SpringBootTest
class SpringBoot01ApplicationTests {
    @Autowired //如果有person对象,则自动注入过来
    private Person person;


    @Test
    public void testPerson(){
        System.out.println(person);
    }
}
  1. 当项目依赖加上下面这个redis的启动器的时候 , 运行testPerson()方法
     <!-redis依赖--->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

在这里插入图片描述

  1. 当项目依赖去除redis的启动器的时候 , 运行testPerson()方法

在这里插入图片描述

3. 分析缺点

  • 上述方法只能判断是否有Redis的依赖加入进来,也就是matches方法中写死了,Class.ForName()参数写了固定的,我需要实现动态的判断,也就是我想判断任意依赖是否添加,来决定是否创建Person对象

4. 完善简易版自动装配

  • 涉及注解
    • @ConditionalOnClass: 这个注解是spring提供的注解,传入一个name[ ]数组,数组中的每一个元素都是一个类的名字ClassName,如果数组中的类全部存在则该Bean注入成功,否则注入失败。
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class) //使用了Conditional注解修饰
public @interface ConditionalOnClass {

	/**
	 * The classes that must be present. Since this annotation is parsed by loading class
	 * bytecode, it is safe to specify classes here that may ultimately not be on the
	 * classpath, only if this annotation is directly on the affected component and
	 * <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
	 * use this annotation as a meta-annotation, only use the {@link #name} attribute.
	 * @return the classes that must be present
	 */
	Class<?>[] value() default {};

	/**
	 * The classes names that must be present.
	 * @return the class names that must be present.
	 */
	String[] name() default {};

}
  • 修改上述步骤:
  1. 使用@ConditionalOnClass的话我们就不需要自己手动写一个类去实现Condition接口,和重写matches方法了,spring已经帮我们写好了实现。

  2. 创建一个PersonConfig配置类,里面根据条件来决定是否要创建Person对象

@Configuration
public class RedisConfig {
    @Bean
    //使用@ConditionalOnClass来进行判断是否要注入该bean
    //当有DispatcherServelt和RedisTemplate的类都存在的时候才注入person对象
    @ConditionalOnClass(name = {"org.springframework.web.servlet.DispatcherServlet",
    						"org.springframework.data.redis.core.RedisTemplate"}})
    public Person person(){
        return new Person();
    }
}
  1. 测试:
    • 当我添加了spring-boot-starter-webspring-boot-starter-data-redis的时候
      在这里插入图片描述
    • 当我去除了redis依赖只剩下web依赖的时候
      在这里插入图片描述

总结:

  • 为什么springboot会在你添加了某些依赖就自动创建某些对象,而你不加这些依赖就不给你创建这些对象?
  • 暂时可以理解为:因为springboot内部创建bean也就是一些依赖需要用到的核心对象的时候,并不是无脑使用@Bean来创建的,而是还搭配用到很多@ConditionalXXX的注解,要满足传入注解中的条件的时候,这些核心对象才会被创建,这些条件可能是只有加了一些依赖或者叫启动器的时候才会满足,不加的话就不满足,自然就不会创建对象。这样就做到了按需创建对象,用户需要什么对象springboot就帮你创建好,并放到spring容器中,用户直接使用就可以了。
  • 一些spring已经写好的@ConditionalXXX注解:
    • @ConditionalOnBean:仅在当前上下文中存在某个对象时,才会初始化一个Bean
    • @ConditionalOnMissingBean:仅在当前上下文中不存在某个对象时,才会初始化一个Bean
    • @ConditionalOnExpression:当表达式为true时,才会初始化一个Bean
    • @ConditionalOnMissingClass:某个class类位于路径上不存在时,才会实例化一个Bean
    • @ConditionalOnClass :某个class位于类路径上,才会实例化一个Bean
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:50:24  更:2022-08-19 18:52:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:53:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码