条件加载作用
Spring条件加载是根据我们的业务需求来加载对应的bean,而不是加载所有的bean,也就是选择性加载,它是通过Spring 4的一个注解@Conditional实现的。
@Conditional源码解析
@Conditional源码
由Conditional源码可见,它可以标注在类上也可以标注在方法上。内部主要利用了condition这个接口判断是否满足条件,从而决定是否需要加载对应的bean。
其中value的类型是一个数组,也就是它支持多个condition接口的实现配置。如果你配置了多个condition接口,那么所有的condition都需要满足条件才会被加载成bean,也就是多个Condition中的match方法全部返回true。
@Condition源码
Condition中的match方法第一个参数ConditionContext
- BeanDefinitionRegistry getRegistry()
可以获取bean的定义。BeanDefinitionRegistry是bean定义的一个注册器,我们通过它就能够获取到当前IOC容器里面所有已经注册的bean - ConfigurableListableBeanFactory getBeanFactory()
用于获取bean的工厂,也就可以获取容器中所有的bean对象。 - Environment getEnvironment()
获取当前工程环境中的所有配置信息 - ResourceLoader getResourceLoader()
资源信息 - ClassLoader getClassLoader()
类加载信息
Condition中的match方法第二个参数AnnotatedTypeMetadata
被检查方法或者是注解的原数据,通过它获取到注解的属性。spring中有很多原数据信息用于描述类或者描述方法以及描述注解的。spring中需要去解析类的信息,比如说,类中的方法,类上的注解,这些都可以称为类的元数据。
@Conditional的使用示例
标注在类上
配置文件
conditional:
flag: true
Condition实现类
package com.imooc.engineering.guide.conditional.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return "true"
.equals(context.getEnvironment().getProperty("conditional.flag"));
}
}
被条件标注的类
package com.imooc.engineering.guide.conditional;
import com.imooc.engineering.guide.conditional.condition.MyCondition;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
@Conditional(MyCondition.class)
@Component
public class MyConditionalComponent {
public void doSomething() {
System.out.println("MyConditionalComponent is active!");
}
}
只有当 MyCondition 中定义的条件为真时,MyConditionalComponent 这个类才会被实例化和使用。
标注在方法上
配置文件
datasource:
type: mysql
创建一个条件判断类,例如根据系统属性判断是否使用特定的数据库:
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class UseMySQLCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String dbType = context.getEnvironment().getProperty("datasource.type");
return "mysql".equalsIgnoreCase(dbType);
}
}
创建数据库连接配置类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
@Configuration
public class DatabaseConfig {
@Autowired
private Environment environment;
@Conditional(UseMySQLCondition.class)
@Bean
public DriverManagerDataSource mysqlDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(environment.getProperty("mysql.url"));
dataSource.setUsername(environment.getProperty("mysql.username"));
dataSource.setPassword(environment.getProperty("mysql.password"));
return dataSource;
}
}
只有当系统属性 datasource.type 的值为 mysql 时,才会创建并注册 mysqlDataSource 这个方法的返回值作为 Bean注册到Spring IOC容器
SpringBoot对Spring条件注解的扩展
包路径:org.springframework.boot.autoconfigure.condition
@ConditionalOnProperty 根据特定的属性进行条件注入
@ConditionalOnBean IOC容器中存在指定的Bean进行条件注入
@ConditionalOnMissingBean IOC容器中不存在指定的Bean进行条件注入
@ConditionalOnClass JVM中存在指定的Class进行条件注入
@ConditionalOnMissingClass 当SpringIoc容器内不存在指定Class的条件
@ConditionalonExpression 基于SpEL表达式作为判断条件
@ConditionalOnJava 基于JVM版本作为判断条件
@ConditionaLOnJndi 在JNDI存在时查找指定的位置
@ConditionalOnNotWebApplication 当前项目不是Web项目的条件
@ConditionalOnRescurce 类路径是否有指定的值
@ConditionalOnSingleCandidate 当指定Bean在SpringIoc容器内只有一个,或者虽然有多个但是指定首选的Bean
@ConditionalOnWebApplication 当前项目是Web项目的条件
应用场景
常见应用场景:
- 环境特定的配置:根据不同的运行环境(如开发、测试、生产)来决定是否加载某些配置类或启用某些功能。
- 依赖存在性:只有当某些特定的 Bean 存在于 Spring 容器中时,才加载或执行相关的配置或方法。
- 类的存在性:根据某些特定类在类路径中是否存在来决定配置的加载。
- 系统属性或环境变量:基于特定的系统属性或环境变量的值来控制组件的启用。
- Java 版本:根据运行时的 Java 版本来决定是否加载某些功能。
- 表达式判断:通过复杂的表达式来综合判断是否满足条件。