@Conditional条件装配
- @Conditional是Spring Framework提供的一个核心功能注解,这个注解的作用是提供自动装配的条件限制,一般我们在用@Configuration,@Bean的时候使用它。
- 也就是我们在自定义Bean的注入的时候,我们可以通过@Condition来对bean的注入增加逻辑判断,符合我们要求的我们才让他自动装配
@Conditional 的使用
- 如下注解源码是@Condition
@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);
}
- condition是一个函数式接口,提供了一个matches方法,主要提供一个条件匹配的规则,返回表示是否可以注入Bean。
- @Conditional 的注解来声明如下,他可以接受接收一个Condition的数组
@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使用Demo
- 我们通过对以上Conditional的了解来自己实现一个Bean的按自定义条件的装配:
- 定义一个Condition,判断系统来返回是否装配:
/**
* Created by jiamin5 on 2022/3/10.
*/
public class GpCondition implements Condition{
private static final Logger logger = LoggerFactory.getLogger(GpCondition.class);
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String os = context.getEnvironment().getProperty("os.name");
logger.info("GpCondition matthes osName:{}", os);
if(os.contains("Windows")){
return true;
}
return false;
}
}
- 定义配置类,装载一个BeanTestClass
/**
* Created by jiamin5 on 2022/3/10.
*/
@Configuration
public class ConditionConfig {
@Bean
@Conditional(GpCondition.class)
public BeanTestClass beanTestClass(){
return new BeanTestClass();
}
}
- 如上,我们在BeanTestClass上增加了一个@Conditional(GpCondition.class),其中的具体条件就是我们自定义的注入限制条件类。
- 意思就是,当条件满足我们定义的GpCondition的时候,我们就注入,否则不注入。
- 依然在Application启动类中添加对新定义Bean的获取,如下
/**
* @author liaojiamin
* @Date:Created in 11:08 2022/3/7
*/
@SpringBootApplication
@EnableAutoImport
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext ca = SpringApplication.run(Application.class, args);
System.out.println(ca.getBean(FilterFirstObj.class));
BeanTestClass beanTestClass = ca.getBean(BeanTestClass.class);
System.out.println(beanTestClass);
}
}
- 当我们在Mac os上运行,有如下结果
Spring Boot 中的@Conditional
- 在SpringBoot中,有针对@Conditional的扩展,提供了更简单的使用方式,扩张了各种类型的注解,如下:
- ConditionalOnBean/ConditionalOnMissBean 容器中存在或者不存在某个类的时候进行Bean加载
- ConditionalOnClass/ConditionalOnMissClass:classpath下存在或者不存在指定类的时候进行Bean加载
- ConditionalOnCloudPlatform:只允许在指定的云平台上才加载指定Bean
- ConditionalOnExpression:基于SpEl表达式的条件判断
- ConditionalOnJava:只允许在指定版本Java才加载Bean
- ConditionalOnJndi:只有指定资源通过JNDI加载后才加载Bean
- ConditionalOnWebApplication/ConsitionalOnNotWebApplication:如果是活着不是web应用才加载指定的Bean
- ConditionalOnProperty:系统中指定对呀的属性是否有对应值
- ConditionOnResource:要加载的Bean依赖指定资源是否存在于classpath
- ConditionOnSingleCandidate:只有在确定了给定Bean的单个候选项时候才会加载Bean
- 以上这些都在spring-boot-autoconfiguration.jar 中
其他注入方式spring-autoconfigure-metadata
- 除了@Conditional注解。Spring Boot中提供了spring-autoconfigure-metadata.properties文件来实现批量自动装配条件配置
- 与@Conditional意义,只是将条件放在的文件,我们可以在spring-boot-autoconfigure.jar中找到这种配置
- 同样遵循“约定由于配置”,通过这种配置实现条件过滤需保证两个前提条件:
- 如上图中,文件路径名称必须是/META-INF/spring-autoconfigure-metadata.properties
- 配置文件的key’的配置格式:自动配置类的类全路径名.条件 = 值
- 这种配置优点在于可以有效降低Spring Boot启动时间,通过这种过滤方式减少配置陪的加载数量,因为这个过滤发生在配置类的装载之前,所以他可以降低Spring Boot启动时装载Bean的耗时