【小家Spring】Spring注解驱动开发---向Spring Ioc容器中注册Bean的7种方式(中)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】Spring注解驱动开发---向Spring Ioc容器中注册Bean的7种方式(中)

4、@Conditional按照条件向Spring中期中注册Bean

 /*
 * @author Phillip Webb
 * @author Sam Brannen
 * @since 4.0
 * @see Condition
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
  /**
   * All {@link Condition}s that must {@linkplain Condition#matches match}
   * in order for the component to be registered.
   */
  Class<? extends Condition>[] value();
}


这个接口是Spirng4提供出来的。在SpringBoot底层大量的用到了这个接口来按照条件注册Bean。


从注解的属性value来看,我们可以传入Condition条件,因此我们可以传入系统自带的,也可以我们自己去实现这个接口,按照我们的需求来注册Bean


image.png


从上图可以看出,SpringBoot工程中对此接口有大量的实现。本文通过自己的实现,来看看根据条件注册Bean的强大之处。


比如我们要实现如下功能:

如果系统是windows,给容器中注入"bill",如果系统是linux,给容器中注入"linus"


  public class WindowCondition implements Condition{
      /**
       * @param context 判断条件
       * @param metadata 注释信息
       * @return boolean
       */
      @Override
      public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
          Environment environment = context.getEnvironment();
          String property = environment.getProperty("os.name");
          if (property.contains("Windows")) {
              return true;
          }
          return false;
      }
  }


需要注意的是,context还有以下方法:


  // 能获取ioc使用的beanfactory
  ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  // 能获取到类加载器
  ClassLoader classLoader = context.getClassLoader();
  // 获取到环境变量
  Environment environment = context.getEnvironment();
  // 获取到Bean定义的注册类
  BeanDefinitionRegistry registry = context.getRegistry();


LinuxCondition类的写法略。配置类如下:


@Configuration
public class MainConfig2 {
    @Conditional({WindowCondition.class})
    @Bean("bill")
    public Person person01() {
        return new Person("Bill Gates", 60);
    }
    @Conditional({LinuxCondition.class})
    @Bean("linux")
    public Person person02() {
        return new Person("linus", 45);
    }
}

运行:(测试时候可以设置运行时参数:-Dos.name=linux)


结果我们会发现,注册的Bean已经按照我们的条件去注册了

备注:@Conditonal注解不仅可以标注在方法上,还可以标注在类上。如果标注在配置类上,那么若不生效的话,这个配置类所有就将不会再生效了


5、@Improt快速导入一个组件


@Improt快速导入特别重要,在SpringBoot自动装配的过程中起到了非常关键的作用

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
  /**
   * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
   * or regular component classes to import.
   */
  Class<?>[] value();
}


@Import可以导入第三方包,或则自己写的类,比较方便,Id默认为全类名(这个需要注意)

比如新建一个类Color


public class Color {
}


配置类上:

@Import({Color.class})
@Configuration
public class MainConfig2 {}


6、ImportSelector和ImportBeanDefinitionRegistrar


ImportSelector:


从注解中的注释中可以看出,import除了导入具体的实体类外,还可以导入实现了指定接口的类。现在我们自己来实现一个,编写一个MyImportSelector类实现ImportSelector接口

public class MyImportSelector implements ImportSelector{
    // 返回值就导入容器组件的全类名
    // AnnotationMetadata:当前类标注的@Import注解类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {"com.cuzz.bean.Car"};
    }
}

在配置类中,通过@Import导入


@Import({Color.class, MyImportSelector.class})
@Configuration
public class MainConfig2 {}

这样子我们发现,Car类已经被导入进去了。


ImportBeanDefinitionRegistrar:


public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * @param importingClassMetadata 当前类的注解信息
     * @param registry 注册类
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 查询容器
        boolean b = registry.containsBeanDefinition("com.cuzz.bean.Car");
        // 如果有car, 注册一个汽油类
        if (b == true) {
            // 需要添加一个bean的定义信息
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Petrol.class);
            // 注册一个bean, 指定bean名
            registry.registerBeanDefinition("petrol", rootBeanDefinition);
        }
    }
}

配置类:



@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
@Configuration
public class MainConfig2 {}

在SpringBoot中的使用,举个栗子:

注解@ServletComponentScan的解析,从下面代码可以看出:


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {}


是ServletComponentScanRegistrar注册进去和解析的。在看看这个类:


class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {}

它就是个标准的ImportBeanDefinitionRegistrar 。然后在方法registerBeanDefinitions这里面做了很多事:比如添加注解的后置处理器等等


相关文章
|
5天前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
18天前
|
网络安全 Docker 容器
VScode远程服务器之远程 远程容器 进行开发(五)
VScode远程服务器之远程 远程容器 进行开发(五)
20 1
|
25天前
|
存储 持续交付 开发者
掌握Docker容器化:提升开发效率与应用部署
【10月更文挑战第4天】在现代软件开发中,Docker容器化技术因其轻量级、可移植和快速部署的特点,成为提升开发效率和简化部署流程的关键工具。本文介绍了Docker的基本概念、核心组件及其优势,并探讨了如何在开发环境中搭建、微服务架构及CI/CD流程中有效利用Docker,助力软件开发更加高效便捷。
|
17天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
46 0
|
25天前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
41 0
|
3月前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
5月前
|
XML Java 数据格式
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
Spring5系列学习文章分享---第一篇(概述+特点+IOC原理+IOC并操作之bean的XML管理操作)
45 1
|
2月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
189 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
5月前
|
XML druid Java
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
Spring5系列学习文章分享---第二篇(IOC的bean管理factory+Bean作用域与生命周期+自动装配+基于注解管理+外部属性管理之druid)
55 0
|
3月前
|
XML Java 数据格式
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
这篇文章详细介绍了Spring框架中IOC容器的Bean管理,特别是基于XML配置方式的实现。文章涵盖了Bean的定义、属性注入、使用set方法和构造函数注入,以及如何注入不同类型的属性,包括null值、特殊字符和外部bean。此外,还探讨了内部bean的概念及其与外部bean的比较,并提供了相应的示例代码和测试结果。
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)