【フレームソースコード】Springソースコードコアアノテーション @Conditional原則と応用

ここに画像の説明を挿入

1. @Conditional アノテーションとは

  • @Conditionalspring-contextパッケージの下のコメントから来ています。
  • @Conditional を介していくつかの条件判定を設定します。すべての条件が満たされると、@Conditional アノテーションでマークされたターゲットが Spring によって処理されます。
  • たとえば、現在の環境、システムのプロパティ、設定ファイルなどの条件に応じて、Bean を登録するか、特定のコンポーネントを実行するかを決定します。

  • アプリケーションシナリオ

    • 特定の環境では特定のBeanを登録する必要があり、Beanが存在しない場合の登録によく使用されます。
    • 構成ファイル内のプロパティに従って、Bean を登録するかどうかを決定します。
    • OSの種類や現在のシステムのバージョンなどの環境に応じて構成クラスを選択し、実行するかどうかを決定します。

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 条件が true の場合、@Conditional の結果は true になります。

質問: それで、この条件は何ですか?

  • 条件自体はインターフェイスです。ソース コード内のmatchesメソッドは、条件が一致するかどうかを判断します。メソッドには2つのパラメータがあります。

    • context コンテキスト、コンテナ内の Bean 情報を取得します

    • メタデータ: @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 コンテナの最も重要な概念の 1 つであり、コンテナが Bean インスタンスを作成および管理し、Bean 定義情報を抽象化およびカプセル化するための基礎となります。
    • Beanの名前、タイプ、スコープ、属性などのBeanの定義情報を記述します。
    • Beanのスコープの指定、遅延ロードの有無、自動インジェクションの有無など、Beanの作成と管理を詳細に設定・制御できます。
  • BeanDefinition の目的
    • Beanの名前、タイプ、スコープなど、Beanの基本情報を定義します。
    • Bean属性名、型、値などのBean属性情報を定義します。
    • Beanの初期化方法や破棄方法など、Beanのライフサイクル情報を定義します。
    • Bean 間の依存関係、注入メソッドなどを含む、Bean などの依存関係を定義します。
    • アスペクト、通知、ポイントカットなどを含む、Bean およびその他の AOP 情報を定義します。

3. @Conditionalアノテーションの場合の実戦

  • 要件の背景: 現在、システムにはバスケットボールの動員をシミュレートする 2 セットのデータ ソースがあり、1 つは公式で、もう 1 つは補欠であり、公式がプレーできない場合にのみ、補欠がプレーします。

  • コーディングの実際

    バスケットボール選手エンティティ 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,"男");
        }
    
    }
    

    カスタム条件クラス

    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;
        }
    }
    

    ここに画像の説明を挿入

    テストコード

    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);
        }
    

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_47533244/article/details/130657165