【框架源码】Spring源码底层IOC容器加入对象的方式

简介: 【框架源码】Spring源码底层IOC容器加入对象的方式

1.Spring容器加入对象方式简介

  • 使用XML配置文件
  • 在XML配置文件中使用< bean >标签来定义Bean,通过ClassPathXmlApplicationContext等容器来加载并初始化Bean。

使用注解

使用Spring提供的注解,例如@Component、@Service、@Controller、@Repository等注解来标识Bean

然后通过@ComponentScan等注解扫描器来加载并初始化Bean。

使用Java配置

可以使用Java代码来配置Bean,例如使用@Configuration和@Bean注解来定义Bean

然后通过AnnotationConfigApplicationContext等容器来加载并初始化Bean。

使用Import注解

使用@Import注解来引入其他配置类,然后通过容器加载并初始化Bean

@Import注解提供了三种用法

直接Import导入

ImportSelector接口批量

ImportBeanDefinitionRegistrar条件注册

2.import注解导入Bean实操

(1)import注解简介

  • import注解是Spring框架中的一个注解,用于在一个配置类中引入其他配置类或者普通的Java类
  • 通过@Import注解,可以将其他配置类或者Java类中定义的Bean引入到当前配置类中
  • 默认的bean名称是【类全限定名,即包名+类名】
  • (2)import注解源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
  Class<?>[] value();
}
  • 创建汽车相关的接口以及类实体Bean
//汽车接口
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 = "奥迪汽车";
}
  • 创建配置类Manager
@Configuration
@Import(value = {BaoMaCar.class, AoDiCar.class, BenChiCar.class})
public class CarBeanManager {
}
  • 主类测试
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));
    }
}

6cd2b844517a484ba6c66570f7453f75.jpg

3.ImportSelector批量导入Bean实操

(1)importSelector批量导入简介

  • ImportSelector 接口用于实现动态注册Bean的功能,【批量】导入对象到容器里,根据条件动态地选择需要注册的Bean,并加入Spring容器
  • 实现ImportSelector接口,这个接口的selectImports方法会返回一个String数组,数组中的值就是要添加的组件的全类名

(2)importSelector源码

public interface ImportSelector {
  //该方法的返回值是一个String数组,用于指定需要注册的Bean的类名。
  String[] selectImports(AnnotationMetadata importingClassMetadata);
  @Nullable
  default Predicate<String> getExclusionFilter() {
    return null;
  }
}

(3)案例实战

  • 我们还是用Car这几个实体Bean,批量导入到Spring容器,自定义选择器实现ImportSelector接口。
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"};
    }
}
  • 在我们的Manager中修改import值
@Configuration
//只需要引入MyImportSelector即可
@Import(value = {MyImportSelector.class})
public class CarBeanManager {
}
  • 主类测试
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));
    }
}

a70a84cd92214ea8b96464e5c6f2ea6f.jpg

4.BeanDefinitionRegistrar动态注册Bean实操

(1)ImportBeanDefinitionRegistrar接口简介

ImportBeanDefinitionRegistrar是Spring框架中的一个接口,用于实现动态注册Bean的功能

ImportBeanDefinitionRegistrar可以在运行时动态地向Spring容器中注册BeanDefinition

与ImportSelector不同的是,ImportSelector只能返回需要注册的Bean的类名

在使用@Import注解时,将实现ImportBeanDefinitionRegistrar接口的类引入到当前配置类中,实现动态注册Bean的功能

(2)ImportBeanDefinitionRegistrar源码

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)案例实战

  • 现在我们有一个场景,当宝马汽车、奥迪汽车、奔驰汽车都存在时,新创建一个新能源汽车
  • 创建新能源汽车主类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NewEnergyCar implements Car{
    private String name = "新能源汽车";
}
  • 创建自定义的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);
        }
    }
}

配置Manager中import的值

@Configuration
@Import(value = {MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class CarBeanManager {
}
  • 主类测试
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));
    }
}


dff78ef991ae40b8b58a6f40c5eab8ab.jpgb6439398dc504bfbb91e878a73be5481.jpg

77a4b6262f59409e9a467da17db78b71.jpg(4)BeanDefinition 介绍

  • Spring容器中最重要的概念之一,它是容器创建和管理Bean实例的基础,对Bean的定义信息的抽象和封装
  • 描述一个Bean的定义信息,包括Bean的名称、类型、作用域、属性等信息
  • 可以对Bean的创建和管理进行详细的配置和控制,例如可以指定Bean的作用域、是否懒加载、是否自动注入等属性ba5a0be83a93444783dfb4e3d93fb4ab.jpg
相关文章
|
12天前
|
安全 Java 开发者
如何在Spring框架中实现横切关注点的集中管理和重用?
【4月更文挑战第30天】如何在Spring框架中实现横切关注点的集中管理和重用?
18 0
|
12天前
|
安全 Java 程序员
Spring框架的核心特性是什么?
【4月更文挑战第30天】Spring 的特性
17 0
|
20小时前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
12 6
|
1天前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
10 3
|
2天前
|
XML Java 数据库连接
Spring框架与Spring Boot的区别和联系
Spring框架与Spring Boot的区别和联系
10 0
|
4天前
|
前端开发 安全 Java
使用Spring框架加速Java开发
使用Spring框架加速Java开发
10 0
|
4天前
|
设计模式 数据采集 监控
Spring日志框架
Spring日志框架
8 0
|
4天前
|
前端开发 Java 应用服务中间件
Spring MVC框架概述
Spring MVC 是一个基于Java的轻量级Web框架,采用MVC设计模型实现请求驱动的松耦合应用开发。框架包括DispatcherServlet、HandlerMapping、Handler、HandlerAdapter、ViewResolver核心组件。DispatcherServlet协调这些组件处理HTTP请求和响应,Controller处理业务逻辑,Model封装数据,View负责渲染。通过注解@Controller、@RequestMapping等简化开发,支持RESTful请求。Spring MVC具有清晰的角色分配、Spring框架集成、多种视图技术支持以及异常处理等优点。
12 1
|
4天前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
13 1
|
5天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
47 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式