[프레임 소스코드] Spring 소스코드 핵심 주석 @조건부 원리 및 적용

여기에 이미지 설명 삽입

1. @Conditional 어노테이션이란?

  • @Conditionalspring-context패키지 아래의 주석 에서 가져옵니다 .
  • @Conditional을 통해 몇 가지 조건부 판단을 설정하고, 모든 조건이 충족되면 @Conditional 주석이 표시된 대상을 Spring에서 처리합니다.
  • 예를 들어, 현재 환경, 시스템 속성, 구성 파일 및 기타 조건에 따라 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 조건이 true일 때 @Conditional의 결과는 true입니다.

질문: 그렇다면 이 조건은 무엇입니까?

  • 조건 자체는 인터페이스입니다. 소스 코드의 matches 메소드는 조건이 일치하는지 여부를 판단합니다. 메소드에는 두 개의 매개변수가 있습니다.

    • 컨텍스트 컨텍스트, 컨테이너에서 빈 정보 가져오기

    • 메타데이터: @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 정의 레지스터를 반환하며, 이는 나중에 사용할 빈 정의 레지스트리를 얻는 데 사용됩니다.

  • 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의 수명 주기 정보를 정의합니다.
    • 빈 간의 종속성, 주입 방법 등을 포함하여 빈과 같은 종속성을 정의합니다.
    • Aspect, 알림, 포인트컷 등을 포함하여 Bean 및 기타 AOP 정보를 정의합니다.

3. @조건부 주석의 경우 실전

  • 요구 배경: 이제 시스템에는 농구 동원을 시뮬레이션하는 두 세트의 데이터 소스가 있습니다. 하나는 공식이고 다른 하나는 교체입니다. 공식이 경기를 할 수 없는 경우에만 교체 선수가 경기합니다.

  • 실제 코딩

    농구선수 엔티티 bean 생성

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

    빈 구성 클래스 만들기

    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