Spring注解(四):@Conditional根据条件注册组件

简介: 在进行spring注解开发时,如果对于某个bean生成了多个实例,在进行组件注册的时候会全部注入到IOC的容器当中,比如:

在进行spring注解开发时,如果对于某个bean生成了多个实例,在进行组件注册的时候会全部注入到IOC的容器当中,比如:

实体类代码:


package com.xinyi.bean;
public class Person {
  private String name;
  private Integer age;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  @Override
  public String toString() {
    return "Person [name=" + name + ", age=" + age + "]";
  }
  public Person(String name, Integer age) {
    super();
    this.name = name;
    this.age = age;
  }
  public Person() {
  }
}
复制代码


配置类代码:


package com.xinyi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.xinyi.bean.Person;
@Configuration
public class MyConfig1 {
  @Bean("Lin Sin")
  public Person person() {
    return new Person("李青",18);
  }
  @Bean("Yasuo")
  public Person person1() {
    return new Person("亚索",23);
  }
  @Bean("Zed")
  public Person person2() {
    return new Person("劫",32);
  }
}
复制代码


测试类代码:


package com.xinyi.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.xinyi.bean.Person;
import com.xinyi.config.MyConfig1;
public class IOCTest {
  @Test
  public void test3() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig1.class);
    String[] names = applicationContext.getBeanNamesForType(Person.class);
    for(String name:names) {
      System.out.println(name);
    }
        Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);
    System.out.println(persons);
  }
}
复制代码


输出结果:


05266e4ffab347c68908c90fe21472ff~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


三个bean的实例都被注入到IOC容器之中,但是在开发过程中并非所有的bean实例都是需要的,Conditional注解则能够根据不同的需求注入不同的bean实例,@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean,@Conditional注解的源码如下:


//此注解可以标注在类和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
  /**
   * All {@link Condition Conditions} that must {@linkplain Condition#matches match}
   * in order for the component to be registered.
   */
  Class<? extends Condition>[] value();
}
复制代码


@Conditional注解既可以使用在类上,也可以使用在方法上。根据Conditional 注解的源码,在Conditional 注解的参数中需要接受一个Condition(条件)数组,实现Condition 接口的matches方法。


@FunctionalInterface
public interface Condition {
  /**
   * Determine if the condition matches.
   * @param context the condition context
   * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
   * or {@link org.springframework.core.type.MethodMetadata method} being checked
   * @return {@code true} if the condition matches and the component can be registered,
   * or {@code false} to veto the annotated component's registration
   */
  boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
复制代码


通过获取计算机系统的环境注入不同的bean实例,Condition1判断本地系统为windows系统,Condition2判断本地系统如果Linux系统:


package com.xinyi.condition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
//判断是否是windows系统
public class Condition1 implements Condition{
  /**
   * ConditionContext:判断条件能使用的上下文,这里是角色
   * AnnotatedTypeMetadata:当前标注了Condition注解的注释信息
   */
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // 判断角色是否是打野
    //1.能够获取到ioc容器使用的beanfactory
    ConfigurableBeanFactory beanFactory = context.getBeanFactory();
    //2、获取类加载器
    ClassLoader loader = context.getClassLoader();
    //3、获取当前环境信息
    Environment environment=context.getEnvironment();
    //4、获取bean定义的注册类
    BeanDefinitionRegistry registry = context.getRegistry();
    String property = environment.getProperty("os.name");
    if(property.contains("Windows")) {
      return true;
    }
    return false;
  }
}
复制代码


package com.xinyi.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
//判断是否是linux系统
public class Condition2 implements Condition {
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    Environment environment = context.getEnvironment();
    String property = environment.getProperty("os.name");
    if(property.contains("linux")) {
      return true;
    }
    return false;
  }
}
复制代码


给person和person1使用@Conditional注解,并且分别赋值Conditional1和Conditional2,由于本地系统是window10,所以根据Conditional1的条件Lin Sin和未加任何条件的Zed被注入进容器。


package com.xinyi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import com.xinyi.bean.Person;
import com.xinyi.condition.Condition1;
import com.xinyi.condition.Condition2;
@Configuration
public class MyConfig1 {
  //@Scope("prototype")
  //默认单实例
  @Bean("Lin Sin")
  @Lazy
  @Conditional(Condition1.class)
  public Person person() {
    //System.out.println("IOC容器中注入person实例");
    return new Person("李青",18);
  }
  @Conditional(Condition2.class)
  @Bean("Yasuo")
  public Person person1() {
    return new Person("亚索",23);
  }
  @Bean("Zed")
  public Person person2() {
    return new Person("劫",32);
  }
}
复制代码


f0d3e27a07ca4123bbb80f6f9e96fdd2~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


然后右键 run as—>run configurations----->选择Arguments在vm arguments中输入-Dos.name=linux,将运行时的系统环境设为linux系统,则Conditional2的条件Yasuo和未加任何条件的Zed被注入进容器。


53e89aa39a5e443eb8325b2f00cf3f40~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


微信截图_20220517203647.png


@Conditional(Condition1.class)不仅可以作用在方法上还能作用在类上,作用在类上则表示如果满足条件,则类中的所有bean注册都能生效,反之都不能生效。


package com.xinyi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import com.xinyi.bean.Person;
import com.xinyi.condition.Condition1;
import com.xinyi.condition.Condition2;
@Configuration
@Conditional(Condition1.class)
public class MyConfig1 {
  //@Scope("prototype")
  //默认单实例
  @Bean("Lin Sin")
  @Lazy
  @Conditional(Condition1.class)
  public Person person() {
    //System.out.println("IOC容器中注入person实例");
    return new Person("李青",18);
  }
  //@Conditional(Condition2.class)
  @Bean("Yasuo")
  public Person person1() {
    return new Person("亚索",23);
  }
  @Bean("Zed")
  public Person person2() {
    return new Person("劫",32);
  }
}
复制代码


所有的bean都注入到ioc容器中,再修改计算机环境参数,@Conditional注解条件改为linux,则所有组件都不会注入进容器。


f0d3e27a07ca4123bbb80f6f9e96fdd2~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


微信截图_20220517203728.png


以上就是使用@Conditional注解根据条件进行组件的注入。

目录
相关文章
|
8天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
132 73
|
3天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
35 21
|
8天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
8天前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
135 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
58 2
|
2月前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
96 0
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
254 2
|
9天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
16天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
66 14