[Framework source code] The method of adding objects to the underlying IOC container of Spring source code

insert image description here

1. Introduction to the method of adding objects to the Spring container

  • Use XML configuration files
    • Use the <bean> tag in the XML configuration file to define the bean, and load and initialize the bean through containers such as ClassPathXmlApplicationContext.
  • Use annotations
    • Use annotations provided by Spring, such as @Component, @Service, @Controller, @Repository, etc. to identify beans
    • Then load and initialize the Bean through annotation scanners such as @ComponentScan.
  • Configure using Java
    • Beans can be configured using Java code, such as using @Configuration and @Bean annotations to define beans
    • Then load and initialize the Bean through containers such as AnnotationConfigApplicationContext.
  • Use the Import annotation
    • Use the @Import annotation to introduce other configuration classes, and then load and initialize beans through the container
    • The @Import annotation provides three usages
      • Import directly
      • ImportSelector interface batch
      • ImportBeanDefinitionRegistrar condition registration

2. import annotation import Bean operation

(1) Introduction to import annotations

  • The import annotation is an annotation in the Spring framework, which is used to introduce other configuration classes or ordinary Java classes in a configuration class
  • Through the @Import annotation, beans defined in other configuration classes or Java classes can be introduced into the current configuration class
  • The default bean name is [class fully qualified name, that is, package name + class name]

(2) import annotation source code

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    
    
  Class<?>[] value();
}

(3) Import case actual combat

  • Create car-related interfaces and class entity beans
//汽车接口
public interface Car {
    
    
}

//奔驰类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BenChiCar implements Car{
    
    
    private String name = "奔驰汽车";
}

//宝马类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BaoMaCar implements Car{
    
    
    private String name = "宝马汽车";
}

//奥迪类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AoDiCar implements Car{
    
    
    private String name = "奥迪汽车";
}
  • Create a configuration class Manager
@Configuration
@Import(value = {
    
    BaoMaCar.class, AoDiCar.class, BenChiCar.class})
public class CarBeanManager {
    
    
}
  • main class test
public class Main {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //扫描指定的包,包括子包
        context.scan("com.lixiang");
        //里面完成初始化操作,核心方法
        context.refresh();
        Map<String, Car> beansOfType = context.getBeansOfType(Car.class);
        beansOfType.forEach((k,v)-> System.out.println(k+"="+v));
    }
}

insert image description here

3.ImportSelector batch import Bean operation

(1) Introduction to importSelector batch import

  • The ImportSelector interface is used to realize the function of dynamically registering beans, [batch] import objects into the container, dynamically select the beans that need to be registered according to the conditions, and add them to the Spring container

  • Implement the ImportSelector interface, the selectImports method of this interface will return a String array, the value in the array is the full class name of the component to be added

(2) importSelector source code

public interface ImportSelector {
    
    
  //该方法的返回值是一个String数组,用于指定需要注册的Bean的类名。
  String[] selectImports(AnnotationMetadata importingClassMetadata);

  @Nullable
  default Predicate<String> getExclusionFilter() {
    
    
    return null;
  }
}

(3) Actual cases

  • We still use the Car entity beans to import them into the Spring container in batches, and customize the selector to implement the ImportSelector interface.
public class MyImportSelector implements ImportSelector {
    
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
    
    
        return new String[] {
    
    "com.lixiang.domain.AoDiCar","com.lixiang.domain.BaoMaCar","com.lixiang.domain.BenChiCar"};
    }
}
  • Modify the import value in our Manager
@Configuration
//只需要引入MyImportSelector即可
@Import(value = {
    
    MyImportSelector.class})
public class CarBeanManager {
    
    
}
  • main class test
public class Main {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //扫描指定的包,包括子包
        context.scan("com.lixiang");
        //里面完成初始化操作,核心方法
        context.refresh();
        Map<String, Car> beansOfType = context.getBeansOfType(Car.class);
        beansOfType.forEach((k,v)-> System.out.println(k+"="+v));
    }
}

insert image description here

4. BeanDefinitionRegistrar dynamic registration Bean operation

(1) Introduction to the ImportBeanDefinitionRegistrar interface

  • ImportBeanDefinitionRegistrar is an interface in the Spring framework, which is used to realize the function of dynamically registering beans
  • ImportBeanDefinitionRegistrar can dynamically register BeanDefinition with Spring container at runtime
  • Unlike ImportSelector, ImportSelector can only return the class name of the Bean that needs to be registered
  • When using the @Import annotation, introduce the class that implements the ImportBeanDefinitionRegistrar interface into the current configuration class to realize the function of dynamically registering the Bean

(2) ImportBeanDefinitionRegistrar source code

public interface ImportBeanDefinitionRegistrar {
    
    

  /**
    * @param importBeanNameGenerator 
    * @param annotationMetadata 当前类的注解相关信息
    * @param registry IOC容器里面bean的注册信息
    */
  default void registerBeanDefinitions(
    AnnotationMetadata importingClassMetadata, 
    BeanDefinitionRegistry registry,
    BeanNameGenerator importBeanNameGenerator) {
    
    

    registerBeanDefinitions(importingClassMetadata, registry);
  }

  /**
    * @param annotationMetadata 当前类的注解相关信息
    * @param registry IOC容器里面bean的注册信息
    */
  default void registerBeanDefinitions(
    AnnotationMetadata importingClassMetadata, 
    BeanDefinitionRegistry registry) {
    
    
  }

}

(3) Actual cases

  • Now we have a scenario, when BMW, Audi, and Mercedes-Benz all exist, create a new energy vehicle
  • Create the main class of new energy vehicles
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NewEnergyCar implements Car{
    
    
    private String name = "新能源汽车";
}
  • Create a custom ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
    
    
        /**
         * 可以通过该方法进行手动注册
         */
        boolean adCar = beanDefinitionRegistry.containsBeanDefinition("com.lixiang.domain.AoDiCar");
        boolean bmCar = beanDefinitionRegistry.containsBeanDefinition("com.lixiang.domain.BaoMaCar");
        boolean bcCar = beanDefinitionRegistry.containsBeanDefinition("com.lixiang.domain.BenChiCar");

        if (adCar && bmCar && bcCar){
    
    
            //IOC容器加个混合对象
            BeanDefinition beanDefinition = new RootBeanDefinition(NewEnergyCar.class);
            beanDefinitionRegistry.registerBeanDefinition("newEnergyCar",beanDefinition);
        }
    }
}
  • Configure the value of import in Manager
@Configuration
@Import(value = {
    
    MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class CarBeanManager {
    
    
}
  • main class test
public class Main {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //扫描指定的包,包括子包
        context.scan("com.lixiang");
        //里面完成初始化操作,核心方法
        context.refresh();
        Map<String, Car> beansOfType = context.getBeansOfType(Car.class);
        beansOfType.forEach((k,v)-> System.out.println(k+"="+v));
    }
}

insert image description hereinsert image description hereinsert image description here

insert image description here

(4) Introduction to BeanDefinition

  • One of the most important concepts in the Spring container, it is the basis for the container to create and manage Bean instances, abstraction and encapsulation of 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, etc.
    insert image description here

Guess you like

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