[Frame source code] Spring source code core annotation @Conditional principle and application

insert image description here

1. What is @Conditional annotation

  • @ConditionalIt comes from spring-contexta comment under the package.
  • Configure some conditional judgments through @Conditional. When all conditions are met, the target marked by the @Conditional annotation will be processed by Spring.
  • For example, according to the current environment, system properties, configuration files and other conditions to decide whether to register a Bean or execute a certain component.

  • Application Scenario

    • In a specific environment, a specific bean needs to be registered. It is commonly used to register when the bean does not exist.
    • According to a property in the configuration file to decide whether to register the bean.
    • Select the configuration class according to the environment, such as the operating system type and version of the current system to determine whether to execute it.

2. @Conditional annotation source code analysis

  • It can be found through his annotations that he is a purely functional annotation, he does not depend on other annotations, and there are only three meta-annotations on the class .
@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: an array of Condition type, Condition is an interface, which represents a conditional judgment, and there is a method inside to return true or false
  • When all Condition conditions are true, the result of @Conditional is true

Question: So what is this Condition?

  • Condition itself is an interface. The matches method in the source code judges whether the condition matches. There are two parameters in the method:

    • context context, get the bean information in the container

    • metadata: Get all the annotation information on the object marked by @Conditional

    public interface Condition {
          
          
      //判断条件是否匹配
      boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
    }
    
  • Let's take a look at the source code of ConditionContext

public interface ConditionContext {
    
    

  //返回bean定义注册器,用于获取Bean定义的注册表,可以用来注册和获取bean定义的各种配置信息
  BeanDefinitionRegistry getRegistry();

  //用于获取Bean工厂,可以用来获取或操作Bean实例,相当于一个ioc容器对象
  ConfigurableListableBeanFactory getBeanFactory();

  //用于获取环境变量和属性值等配置信息
  Environment getEnvironment();

  //用于获取资源文件,比如XML文件、图片、文本等
  ResourceLoader getResourceLoader();

 //用于获取类加载器,可以用来加载类或资源文件
  ClassLoader getClassLoader();

}
  • The main thing here is BeanDefinitionRegistry, which returns the bean definition register, which is used to obtain the bean definition registry, which we will use later.

  • BeanDefinitionRegistry source code

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

}
  • Introduction to BeanDefinitions
    • BeanDefinition is one of the most important concepts in the Spring container. It is the basis for the container to create and manage Bean instances, abstracting and encapsulating Bean definition information
    • Describe the definition information of a bean, including the bean's name, type, scope, attributes and other information
    • Bean creation and management can be configured and controlled in detail, such as specifying the scope of the Bean, whether it is lazy loaded, whether it is automatically injected, and other attributes.
  • The purpose of BeanDefinition
    • Define the basic information of the Bean, including the name, type, and scope of the Bean.
    • Define Bean attribute information, including Bean attribute name, type, value, etc.
    • Define the life cycle information of the Bean, including the initialization method and destruction method of the Bean.
    • Define dependencies such as beans, including dependencies between beans, injection methods, etc.
    • Define Bean and other AOP information, including aspects, notifications, pointcuts, etc.

3. @Conditional annotation case actual combat

  • Requirement background: Now the system has two sets of data sources, simulating basketball mobilization, one is official, and the other is substitute. Only when the official one cannot play, the substitute will play.

  • Coding in action

    Create a basketball player entity bean

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

    Create a bean configuration class

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

    Custom Condition class

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

    insert image description here

    test code

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

insert image description here
insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/weixin_47533244/article/details/130657165