【框架源码】Spring源码核心注解@Conditional原理及应用

简介: 【框架源码】Spring源码核心注解@Conditional原理及应用

1.什么是@Conditional注解

  • @Conditional来源于spring-context包下的一个注解。
  • 通过@Conditional配置一些条件判断,当所有条件都满足时,被该@Conditional注解标注的目标才会被Spring处理。
  • 例如根据当前环境、系统属性、配置文件等条件来决定是否注册某个Bean或执行某个组件。
  • 应用场景
  • 在某个特定的环境下,需要注册一个特定的Bean,常用的是当bean不存在的时候才注册。
  • 根据配置文件中的某个属性来决定是否注册Bean。
  • 根据环境选择配置类,比如当前系统的操作系统类型、版本等条件来决定是否要执行。

2.@Conditional注解源码解析

  • 通过他的注解内部可以发现,他就是一个纯功能性注解,他并没有依赖于其他注解,类上只有三个元注解
@Target({ElementType.TYPE, ElementType.METHOD})  //注解作用范围在接口、类、枚举、注解、方法
@Retention(RetentionPolicy.RUNTIME) //保留到运行期,jvm加载class文件之后,仍然存在
@Documented  //生成javadoc文档
public @interface Conditional {
  /**
   * All {@link Condition} classes that must {@linkplain Condition#matches match}
   * in order for the component to be registered.
   */
  Class<? extends Condition>[] value();
}
  • value:Condition类型的数组,Condition是一个接口,表示一个条件判断,内部有个方法返回true或false
  • 当所有Condition条件都成立,@Conditional的结果才成立
  • 疑问:那这个Condition又是个啥?
  • Condition本身是个接口,源码中matches方法判断条件是否匹配,方法中有两个参数:
  • context 上下文,获取容器中的bean的信息
  • metadata:获取被@Conditional标注的对象上的所有注解信息
public interface Condition {
  //判断条件是否匹配
  boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
  • 我们再来看看ConditionContext的源码
public interface ConditionContext {
  //返回bean定义注册器,用于获取Bean定义的注册表,可以用来注册和获取bean定义的各种配置信息
  BeanDefinitionRegistry getRegistry();
  //用于获取Bean工厂,可以用来获取或操作Bean实例,相当于一个ioc容器对象
  ConfigurableListableBeanFactory getBeanFactory();
  //用于获取环境变量和属性值等配置信息
  Environment getEnvironment();
  //用于获取资源文件,比如XML文件、图片、文本等
  ResourceLoader getResourceLoader();
 //用于获取类加载器,可以用来加载类或资源文件
  ClassLoader getClassLoader();
}
  • 这里面主要的是BeanDefinitionRegistry ,返回bean定义注册器,用于获取Bean定义的注册表,也是我们一会要用到的。
  • BeanDefinitionRegistry 源码
public interface BeanDefinitionRegistry extends AliasRegistry {
  //用于向Bean定义注册表中注册一个Bean定义,参数beanName表示Bean的名称,beanDefinition表示Bean的定义信息
  void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
  //从Bean定义注册表中移除指定名称的Bean定义,参数beanName表示要移除的Bean名称
  void removeBeanDefinition(String beanName) ;
  //获取指定名称的Bean定义,参数beanName表示要获取的Bean名称
  BeanDefinition getBeanDefinition(String beanName) ;
  //判断指定名称的Bean定义是否存在于注册表中,参数beanName表示要判断的Bean名称 
  boolean containsBeanDefinition(String beanName);
  //获取所有Bean定义的名称,返回一个String数组
  String[] getBeanDefinitionNames();
  //获取Bean定义的数量。
  int getBeanDefinitionCount();
  //判断指定名称的Bean是否已经被使用,参数beanName表示要判断的Bean名称。如果该名称已经被使用,则返回true,否则返回false
  boolean isBeanNameInUse(String beanName);
}

BeanDefinition简介

BeanDefinition是Spring容器中最重要的概念之一,他是容器创建和管理Bean实例的基础,对Bean的定义信息的抽象和封装

描述一个Bean的定义信息,包括Bean的名称、类型、作用域、属性等信息

可以对Bean的创建和管理进行详细的配置和控制,例如可以指定Bean的作用域、是否懒加载、是否自动注入等属性。

BeanDefinition的用途

定义Bean的基本信息,包括Bean的名称、类型、作用域等。

定义Bean的属性信息,包括Bean的属性名称、类型、值等。

定义Bean的生命周期信息,包括Bean的初始化方法、销毁方法等。

定义Bean等依赖关系,包括Bean之间的依赖关系、注入方式等。

定义Bean等AOP信息,包括切面、通知、切点等。

3.@Conditional注解案例实战

  • 需求背景:现在系统有两套数据源,模拟篮球远动员,一个正式的,一个替补的,只有当正式的不能上场时,替补的才会上场。
  • 编码实战

创建篮球运动员实体Bean

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BasketballPlayers {
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private int age;
    /**
     * 性别
     */
    private String sex;
}

创建Bean的配置类

public class BasketballPlayersConfig {
    @Bean("lixiang")
    public BasketballPlayers BasketballPlayers1(){
        return new BasketballPlayers("李祥",18,"男");
    }
    @Bean("zhangsan")
    public BasketballPlayers BasketballPlayers2(){
        return new BasketballPlayers("张三",18,"男");
    }
}

自定义Condition类

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
        //不存在,才返回true
        boolean flag = !registry.containsBeanDefinition("lixiang");
        return flag;
    }
}

8f94f22580b342a5ad59c9cfea9cd8d0.jpg

测试代码

public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //扫描指定的包,包括子包
        context.scan("com.lixiang");
        //里面完成初始化操作,核心方法
        context.refresh();
        Map<String, BasketballPlayers> beansOfType = context.getBeansOfType(BasketballPlayers.class);
        System.out.println(beansOfType);
    }

7bee40e834124d9dbad33c4e87473644.jpg


613c91f8a2e3405395356719856098a1.jpg


90061034cb194735b9396fe0d9c1bc5b.jpg


相关文章
Java也能快速搭建AI应用?一文带你玩转Spring AI可落地性
Java语言凭借其成熟的生态与解决方案,特别是通过 Spring AI 框架,正迅速成为 AI 应用开发的新选择。本文将探讨如何利用 Spring AI Alibaba 构建在线聊天 AI 应用,并实现对其性能的全面可观测性。
Spring AI与DeepSeek实战一:快速打造智能对话应用
在 AI 技术蓬勃发展的今天,国产大模型DeepSeek凭借其低成本高性能的特点,成为企业智能化转型的热门选择。而Spring AI作为 Java 生态的 AI 集成框架,通过统一API、简化配置等特性,让开发者无需深入底层即可快速调用各类 AI 服务。本文将手把手教你通过spring-ai集成DeepSeek接口实现普通对话与流式对话功能,助力你的Java应用轻松接入 AI 能力!虽然通过Spring AI能够快速完成DeepSeek大模型与。
141 11
Java 也能快速搭建 AI 应用?一文带你玩转 Spring AI 可观测性
Java 也能快速搭建 AI 应用?一文带你玩转 Spring AI 可观测性
Spring AI Alibaba 应用框架挑战赛圆满落幕,恭喜获奖选手
第二届开放原子大赛 Spring AI Alibaba 应用框架挑战赛决赛于 2 月 23 日在北京圆满落幕。
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
Java 也能快速搭建 AI 应用?一文带你玩转 Spring AI 可观测性
Java 也能快速搭建 AI 应用?一文带你玩转 Spring AI 可观测性
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
108 7
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
61 12
SpringBoot项目打包成war包
通过上述步骤,我们成功地将一个Spring Boot应用打包成WAR文件,并部署到外部的Tomcat服务器中。这种方式适用于需要与传统Servlet容器集成的场景。
36 8

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等