SpringBoot学习笔记三-原理分析

SpringBoot学习笔记三-原理分析

  • SpringBoot自动装配
    • 1.1 案例
    • 1.2 通过注解方式管理Bean
    • 1.3 小结
    • 1.4 Enable注解
    • 1.5 Import注解
      • 1.5.1 ImportSelector实现类
      • 1.5.2 导入ImportBeanDefinitionRegistrar
    • 1.5 EnableAutoConfiguration
    • 1.6 案例

SpringBoot自动装配

当再pom.xml中导入对应的依赖,那么就可以在SpringBoot的IOC容器中获取该依赖中相应的Bean实例:
比如导入redis依赖:


  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>

那么可以在IOC容器获取bean实例redisTemplate:

ConfigurableApplicationContext context = SpringApplication.run(SpringConditionApplication.class, args);
Object redisTemplate = context.getBean("redisTemplate");
System.out.println(redisTemplate);

1.1 案例

Condition案例:通过设定条件来决定手动创建的Bean是否导入IOC容器
条件:当Jedis在类路径上可用时,才能将创建的Bean注入IOC容器:

(1)首先编写condition类

		package com.rql.condition;
		
		import org.springframework.context.annotation.Condition;
		import org.springframework.context.annotation.ConditionContext;
		import org.springframework.core.type.AnnotatedTypeMetadata;
		
		public class ClassCondition implements Condition {
		    @Override
		    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		       //1.判断Jedis坐标是否导入
		
		        boolean flag = true;
		        try {
		            Class<?> aClass = Class.forName("redis.clients.jedis.Jedis");
		
		        } catch (ClassNotFoundException e) {
		            flag=false;
		        }
		
		        return flag;
		    }
		}


在配置类中,根据ClassCondition 中的matches方法的返回值来决定是否将Bean注入IOC容器

		package com.rql.config;
		import com.rql.condition.ClassCondition;
		import com.rql.domain.User;
		import org.springframework.context.annotation.Bean;
		import org.springframework.context.annotation.Conditional;
		import org.springframework.context.annotation.Configuration;
		
		@Configuration
		public class UserConfig {
		    @Bean
		    @Conditional(ClassCondition.class)
		    public User user() {
		        return new User();
		    }
		}


最后,获取注入的Bean实例:

		ConfigurableApplicationContext context = SpringApplication.run(SpringConditionApplication.class, args);
		Object user = context.getBean("user");
		System.out.println(user);

可以发现,如果没有在pom.xml导入Jedis依赖的话,那么matches方法返回的值就为false,那么Bean User就会注入失败,最终结果会报错,找不到对应的Bean实例。

1.2 通过注解方式管理Bean

通过注解的方式可以让条件的复用性更强:
(1)首先,在配置类中,将注入user到IOC容器,这里设置了条件:

@Configuration
public class UserConfig {


    @Bean
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User user() {
        return new User();
    }
}

(2)定义了一个自定义的注解(annotation)叫做 ConditionOnClass。注解在Java中是一种元数据(metadata)机制,它允许你为代码添加额外的信息,这些信息可以在运行时被读取和处理。ConditionOnClass 注解被用于条件性地创建或配置Spring框架中的Bean。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
    String[] value();
}

(3)创建ClassCondition 类需要实现 Condition 接口,并定义条件逻辑

public class ClassCondition implements Condition {
    /**
     *
     * @param context 上下文对象,用于获取环境,IOC容器,ClassLoader对象
     * @param metadata 注解元对象,可以用于获取注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
       //1.判断Jedis坐标是否导入
        Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        System.out.println(map);
        String[] value = (String[]) map.get("value");
        boolean flag = true;
        for (String s : value) {
            try {
                Class.forName(s);
            } catch (ClassNotFoundException e) {
                flag=false;
            }
        }
        return flag;
    }
}

1.3 小结

在这里插入图片描述

1.4 Enable注解

下面主要演示在两个不同的module下,一个module使用另一个module的Bean实例:
(1)首先创建两个module
在这里插入图片描述
(2)在spring-enable-other中创建并注入bean user
在这里插入图片描述

package com.rql.domain;

public class User {
}

@Configuration
public class UserConfig {


    @Bean
    public User user() {
        return new User();
    }
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(UserConfig.class)
public @interface EnableUser {
}

然后在spring-enable上使用user

@SpringBootApplication
//@Import(UserConfig.class)
@EnableUser
public class SpringEnableApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(SpringEnableApplication.class, args);
        Object user = context.getBean("user");
        System.out.println(user);
    }

}

其实,这里本质还是使用了@Import注解,因为在EnableUser中使用了@Import导入了UserConfig类。所以在spring-enable中通过@EnableUser可以加载到user实例

1.5 Import注解

在这里插入图片描述

1.5.1 ImportSelector实现类

(1)导入ImportSelector实现类

创建类并实现ImportSelector接口:

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.rql.domain.User","com.rql.domain.Role"};
    }
}

(2)直接通过Import注解导入,即可

@SpringBootApplication
//@Import(UserConfig.class)
//@EnableUser
@Import(MyImportSelector.class)
public class SpringEnableApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(SpringEnableApplication.class, args);
        Object user = context.getBean("user");
        System.out.println(user);


        Object role = context.getBean("role");
        System.out.println(role);
    }

}

1.5.2 导入ImportBeanDefinitionRegistrar

(1)同样,创建类,继承ImportBeanDefinitionRegistrar接口

public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        registry.registerBeanDefinition("user", beanDefinition);
       //这里直接将Bean注册到IOC容器中
    }
}

(2)在类中导入MyImportBeanDefinitionRegister ,即可获取Bean

@SpringBootApplication
//@Import(UserConfig.class)
//@EnableUser
//@Import(MyImportSelector.class)
@Import(MyImportBeanDefinitionRegister.class)
public class SpringEnableApplication {

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(SpringEnableApplication.class, args);
//        Object user = context.getBean("user");
//        System.out.println(user);

        Object role = context.getBean("user");
        System.out.println(role);
    }
}

上述的四种用法主要目的都是将Bean注入到IOC容器,具体涉及到的应用场景后续再补充。

1.5 EnableAutoConfiguration

在这里插入图片描述

1.6 案例

在这里插入图片描述在这里插入图片描述
(1)创建redis-spring-boot-autoconfigure模块

在这里插入图片描述

(2)创建redis-spring-boot-starter模块,并依赖于redis-spring-boot-autoconfigure模块

在这里插入图片描述在这里插入图片描述

(3)在redis-spring-boot-autoconfigure模块初始化Jedis的Bean,并定义META-INF/spring.factories文件
在这里插入图片描述
RedisProperties:

@ConfigurationProperties(prefix = "redis")//用于将配置文件中的属性绑定到Java对象上。
public class RedisProperties {

    private String host="127.0.0.1";
    private Integer port=6379;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    @Override
    public String toString() {
        return "RedisProperties{" +
                "host='" + host + '\'' +
                ", port=" + port +
                '}';
    }
}

spring.factories文件


org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.rql.redis.config.RedisAutoConfiguration

Spring Boot在启动时自动加载并应用com.rql.redis.config.RedisAutoConfiguration这个类。这个类的bean会在Spring容器中自动注册。

(4)在测试模块导入自定义的redis-starter依赖,并获取Jedis的Bean,操作redis

首先,需要另一个模块导入自定义的redis-starter依赖:

     <dependency>
            <groupId>com.rql</groupId>
            <artifactId>redis-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

然后获取Jedis的Bean,操作redis

        Jedis jedis = context.getBean(Jedis.class);
        System.out.println(jedis);

        jedis.set("name","itcast");
        String name = jedis.get("name");
        System.out.println(name);

上述的过程其实就是在模拟SpringBoot自动装配的原理,通过自定义启动类并进行相应的配置。使用时,只需将自定义的启动类导入,即可获取自定义的Bean实例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/531031.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ceph集群搭建

一、前言 本次搭建ceph集群&#xff0c;使用centos7版本的系统&#xff0c;最高支持ceph版本为15.2.13&#xff0c;如需更高的版本需要使用centos8版本以上的系统&#xff0c;使用cephadm进行搭建&#xff0c;Cephadm 是一个用于部署、管理和监控 Ceph 集群的工具&#xff0c;它…

Towards IP Geolocation Using Delay and TopologyMeasurements(TBG)(2006年)

下载地址:Towards IP geolocation using delay and topology measurements | Proceedings of the 6th ACM SIGCOMM conference on Internet measurement 被引次数:492 Katz-Bassett E, John J P, Krishnamurthy A, et al. Towards IP geolocation using delay and topology …

【鸿蒙开发】系统组件Column

Column组件 Column沿垂直方向布局的容器。 接口&#xff1a; Column(value?: {space?: string | number}) 参数&#xff1a; 参数名 参数类型 必填 参数描述 space string | number 否 纵向布局元素垂直方向间距。 从API version 9开始&#xff0c;space为负数或者…

洪水预警:如何通过数据可视化提前应对灾害

数据可视化在应对洪涝灾害问题中发挥着重要作用。洪涝灾害是一种常见而严重的自然灾害&#xff0c;给人们的生命、财产和生活带来了巨大的威胁和损失。而数据可视化技术通过将海量的数据转化为直观、易懂的图表、图像或地图等形式&#xff0c;帮助人们更好地理解洪涝灾害的发生…

PostgreSQL入门到实战-第十三弹

PostgreSQL入门到实战 PostgreSQL数据过滤(六)官网地址PostgreSQL概述PostgreSQL中IN命令理论PostgreSQL中IN命令实战更新计划 PostgreSQL数据过滤(六) 使用PostgreSQL IN运算符来检查值是否与列表中的任何值匹配 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容…

宁波宠物展|2024中国(宁波)国际宠物用品博览会

中国(宁波)国际宠物用品博览会 地点&#xff1a;宁波国际会展中心 时间&#xff1a;2024年11月14-16日 主办单位:凤麟展览(宁波)有限公司 协办单位:浙江省宠物产业协会 宁波市跨境电子商务协会 宁波欧德国际商务咨询服务有限公司 宁波扬扬会议展览有限公司 20000方展览…

大模型的实践应用20-一种内存高效微调技术LISA,效果比LoRA有显著提升

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下大模型的实践应用20-一种内存高效微调技术LISA&#xff0c;效果比LoRA有显著提升。LISA是一种新型的微调技术&#xff0c;全称为Layerwise Importance Sampled AdamW&#xff0c;由UIUC联合LMFlow团队提出。这项技术…

PUBG绝地求生29.1版本加速器推荐 免费低延迟不丢包加速器

绝地求生是一款多人大逃杀游戏&#xff0c;游戏有多张地图可供玩家选择&#xff0c;玩家空投跳伞至地图的各个角落&#xff0c;赤手空拳寻找武器&#xff0c;车辆以及物资&#xff0c;并在多种多样的地形中展开战斗&#xff0c;枪械角色身上可携带4种武器&#xff0c;分别是近战…

绝地求生29.1版本更新后进不去 绝地求生更新后进不去游戏怎么办

绝地求生游戏共有两种主要模式&#xff1a;第一人称模式和第三人称模式。在这两种模式下玩家可以分别进行单排&#xff0c;双排&#xff0c;四人组队或单人匹配四人团队模式。在进入游戏的时候&#xff0c;玩家可以在面板选择第一人称以及第三人称。在双排或四排等组队多人游戏…

为什么说无人机的发展是必然趋势???

随着科技的飞速发展&#xff0c;无人机已经逐渐从军事领域走进了普通人的生活&#xff0c;成为了我们探索天空、捕捉美好瞬间的新工具。今天&#xff0c;就让我带大家一起走进无人机的世界&#xff0c;感受它带来的无限魅力与可能性。 无人机&#xff0c;顾名思义&#xff0c;就…

C# 如何修改项目名称

目录 背景具体步骤1、Visual Studio中修改项目名和程序集名称以及命名空间2、修改项目文件夹名3、修改解决方案里项目的路径4、再次打开解决方案&#xff0c;问题解决步骤总结 名词解释解决方案&#xff08;Solution&#xff09;项目&#xff08;Project&#xff09;程序集&…

【千帆平台】百度智能云千帆AppBuilder应用探索益智游戏之猜物小游戏

欢迎来到《小5讲堂》 这是《千帆平台》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景AppBuilder控制台创建应用设置应用自动配置随机生成AI生成应…

线程池(详解)

目录 前言 线程池的好处 使用Executors 创建常见的线程池 工厂模式: 往线程池当中添加任务 常见线程类 ​编辑 线程池的参数介绍 线程池的工作流程 补充 前言 如果我们需要频繁的创建销毁线程,此时创建销毁线程的成本,不能忽视了 因此就可以使用线程池.提前创建好一波…

Vue - 4( 8000 字 Vue 入门级教程)

一&#xff1a; Vue 初阶 1.1 关于不同版本的 Vue Vue.js 有不同版本&#xff0c;如 vue.js 与 vue.runtime.xxx.js&#xff0c;这些版本主要针对不同的使用场景和需求进行了优化&#xff0c;区别主要体现在以下几个方面&#xff1a; 完整版 vs 运行时版&#xff1a; vue.js&…

标注平台工作流:如何提高训练数据质量与管理效率

世界发展日益依托数据的驱动&#xff0c;企业发现&#xff0c;管理不断增长的数据集却愈发困难。数据标注是诸多行业的一个关键过程&#xff0c;其中包括机器学习、计算机视觉和自然语言处理。对于大型语言模型&#xff08;LLM&#xff09;来说尤是如此&#xff0c;大型语言模型…

代码随想录阅读笔记-回溯【组合总和III】

题目 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 示例 1: 输入: k 3, n 7 输出: [[1,2,4]] 示例 2: 输入: k 3, n 9 输出: [[1,2,6], [1,3,5], [2,3,4]] 说明&#xff1a; 所有数字都是正整数。…

Day30 回溯 LeedCode 332.重新安排行程 51. N皇后 37. 解数独 蓝桥杯 与或异或

332. 重新安排行程 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 JFK…

【小程序】常用方法、知识点汇总1

欢迎来到《小5讲堂》 这是《小程序》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言请求超时Markdown解析逐行显示效果文本变动事件转发…

C语言—每日选择题—Day65

前言 我们的刷题专栏又又又开始了&#xff0c;本专栏总结了作者做题过程中的好题和易错题。每道题都会有相应解析和配图&#xff0c;一方面可以使作者加深理解&#xff0c;一方面可以给大家提供思路&#xff0c;希望大家多多支持哦&#xff5e; 第一题 1、如下代码输出的是什么…

LINUX系统触摸工业显示器芯片应用方案--Model4(简称M4芯片)

背景介绍&#xff1a; 触摸工业显示器传统的还是以WINDOWS为主&#xff0c;但近年来&#xff0c;安卓紧随其后&#xff0c;但一直市场应用情况不够理想&#xff0c;反而是LINUX系统的触摸工业显示器大受追捧呢&#xff1f; 触摸工业显示器传统是以Windows系统为主&#xff0c…