Spring boot条件注解是@ContionalXXX相关的注解,表示当特定条件有效时,被修饰的配置类或配置方法才会生效。
条件注解可以用来修饰@Configuration类或@Bean方法等。
主要有以下行为:
- 当Spring Boot检测到类加载路径包含某个框架时,会自动配置该框架的基础Bean.
- 只有当开发者没配置某些Bean时,Spring Boot才会在容器中自动配置对应的Bean。
- 只有当开发者配置了某些属性时,Spring Boot才会在容器中自动配置对应的Bean。
概述
Spring Boot的条件注解支持如下几类:
类条件注解:
@ConditionalOnClass
:该注解指定的类存在时,被修饰的类或方法生效。可通过value或name属性指定它所要求存在的类,其中value属性值是被检查类的Class对象,name属性值是被检查类的字符串形式的全限定类名
—既然是检查目标类是否存在,那么通常用name属性值居多。@ConditionalOnMissingClass
:该注解指定的类不存在时,被修饰的类或方法生效。value属性值只能是被检查类的字符串形式的全限定类名—既然要确保该类不存在,那么该类对应的Class通常也就不存在了。
Bean条件注解:
@ConditionalOnMissingBean
:目标Bean不存在时,实例化Bean。type是类的全限定名,value是Bean的class类型@ConditionalOnSingleCandidate
:该注解相当于@ConditionalOnBean的增强版,它不仅要求被检查的Bean必须存在,而且只能有一个“候选者”—能满足byType依赖注入的条件。@ConditionalOnBean
:目标Bean存在时,实例化Bean@ConditionalOnMissingFilterBean
:相当于@ConditionalOnMissingBean的特殊版本,它专门用于检查容器中是否存在指定类型的javax.servlet.Filter,因此它只能通过value属性指定其要检查的Filter的类型。
属性条件注解(properties配置):
@ConditionalOnProperty
:用于检查特定属性是否具有指定的属性值,然后根据条件实例化Bean。
资源条件注解:
@ConditionalOnResource
:要求指定的资源必须存在,其修饰的配置类或方法才会生效。使用该注解时只需指定resources属性,该属性指定必须存在的资源。
Web应用条件注解:
@ConditionalOnWebApplication
:当前应用是Web应用,其修饰的配置类或方法生效。其中type有3个值,ANY(任何web应用都生效),SERVLET(Spring MVC情况下生效),REACTIVE(Spring WebFlux情况下生效)@ConditionalOnNotWebApplication
:要求当前应用不是Web应用时,该注解修饰的配置类或方法才会生效。@ConditionalOnWarDeployment
:要求当前应用以传统WAR包方式被部署到Web服务器或应用服务器中时(不以独立Java程序的方式运行),该注解修饰的配置类或方法才会生效。@ConditionalOnNotWarDeployment
:要求当前应用以不是传统WAR包方式被部署到Web服务器或应用服务器中时,该注解修饰的配置类或方法才会生效。
SpEL条件表达式注解:
@ConditionalOnExpression
:要求指定SpEL表达式的值为true时,其所修饰的配置类或方法才会生效。
其他条件注解:
@ConditionalOnCloudPlatform
:要求应用被部署在特定云平台上,这样其修饰的配置类或方法才会生效。该注解可通过value属性指定它所要求的云平台,该value属性支持多个枚举值,详见CloudPlatform枚举类。@ConditionalOnJava
:对目标平台的Java版本进行检测,它既可要求目标平台的Java版本是某个具体的版本,也可要求其高于或低于某个版本。JavaVersion value:指定要求的Java版本。ConditionalOnJava.Range range:该属性支持EQUAL_OR_NEWER(大于或等于value属性指定的版本)和OLDER_THAN(小于value 属性指定的版本)两个枚举值。如果不指定该属性,则要求目标平台的Java版本必须是value属性所指定的版本。@ConditionalOnJndi
:要求指定JNDI必须存在,使用该注解时通过value属性指定要检查的JNDI。@ConditionalOnRepositoryType
:要求特定的Spring Data Repository被启用时,其修饰的配置类或方法才会生效。
示例
新建一个springboot-demo项目,springboot版本3.1.5,java版本17.仅包含spring-boot-starter-web和lombok。
项目启动类SpringbootDemoApplication
:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootDemoApplication {
public static void main(String[] args) {
var ctx = SpringApplication.run(SpringbootDemoApplication.class, args);
//获取MyConfig对应的配置类
System.out.println(ctx.getBean("myConfig"));
System.out.println(ctx.getBean("myBean"));
}
}
此时运行项目,会报异常:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myConfig' available
新建MyConfig和MyBean类:
MyConfig:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
public class MyConfig {
@Bean
public MyBean myBean(){
return new MyBean();
}
}
MyBean:
import lombok.Data;
@Data
public class MyBean {
private String name;
}
此时运行SpringbootDemoApplication,正常启动无报错
@ConditionalOnClass
对MyConfig增加@ConditionalOnClass注解:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
//仅仅当perry.demo.springbootdemo.config.MyService类存在时,该配置类生效
@ConditionalOnClass(name = "perry.demo.springbootdemo.config.MyService")
@Configuration(proxyBeanMethods = false)
public class MyConfig {
@Bean
public MyBean myBean(){
return new MyBean();
}
}
再次运行程序,报异常:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myConfig' available
因为@ConditionalOnClass要求指定的类必须存在。
新建MyService类:
package perry.demo.springbootdemo.config;
import lombok.Data;
@Data
public class MyService {
private String name;
}
再次启动程序,不再报错。
@ConditionalOnMissingClass
当MyConfig类被@ConditionalOnMissingClass
注解修饰时,不存在对应的目标类,才会实例化指定的Bean.
//仅仅当perry.demo.springbootdemo.config.MyService类不存在时,该配置类生效
@ConditionalOnMissingClass(value = "perry.demo.springbootdemo.config.MyService")
public class MyConfig {...}
@ConditionalOnBean
使用@ConditionalOnBean修饰MyConfig
//当存在MyService的Bean时,实例化MyConfig
@ConditionalOnBean(type = "perry.demo.springbootdemo.config.MyService")
public class MyConfig {...}
运行main函数,报如下错误:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myConfig' available
说明MyService类虽然存在,但并没有实例化。所以需实例化才能正常运行。
新建InitComponent类,实例化MyService:
package perry.demo.springbootdemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class InitComponent {
@Bean
public MyService myService(){
MyService myService = new MyService();
myService.setName("test");
return myService;
}
}
再次运行程序,已不报错。
@ConditionalOnMissingBean
@ConditionalOnMissingBean
与@ConditionalOnMissingBean
类似,当不存在MyService的Bean时,实例化MyConfig。
//当不存在MyService的Bean时,实例化MyConfig
@ConditionalOnMissingBean(type = "perry.demo.springbootdemo.config.MyService")
public class MyConfig {}
@ConditionalOnSingleCandidate
//当只存在一个MyService的Bean时,实例化MyConfig
@ConditionalOnSingleCandidate(type = "perry.demo.springbootdemo.config.MyService")
public class MyConfig {}
其他条件注解类似,这里不再列出。
其他注解相关代码如下:
MyConfig类:
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.text.DateFormat;
@Configuration(proxyBeanMethods = false)
//仅仅当perry.demo.springbootdemo.config.MyService类存在时,该配置类生效
//@ConditionalOnClass(name = "perry.demo.springbootdemo.config.MyService")
//仅仅当perry.demo.springbootdemo.config.MyService类不存在时,该配置类生效
//@ConditionalOnMissingClass(value = "perry.demo.springbootdemo.config.MyService")
//当存在MyService的Bean时,实例化MyConfig
//@ConditionalOnBean(type = "perry.demo.springbootdemo.config.MyService")
//当只存在一个MyService的Bean时,实例化MyConfig
@ConditionalOnSingleCandidate(type = "perry.demo.springbootdemo.config.MyService")
//当不存在MyService的Bean时,实例化MyConfig
//@ConditionalOnMissingBean(type = "perry.demo.springbootdemo.config.MyService")
public class MyConfig {
@Bean
public MyBean myBean(){
return new MyBean();
}
// @Bean
//存在下述属性,才会实例化Bean
// @ConditionalOnProperty(name = "mytest",prefix = "perry.demo",havingValue = "ball")
//Spring MVC情况下生效
// @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// @ConditionalOnWarDeployment
// @ConditionalOnNotWarDeployment
//下述表达式myService.name 代表 InitComponent 类中 myService bean的name属性
// @ConditionalOnExpression("myService.name eq \"test1\"")
//// @ConditionalOnCloudPlatform()
//// @ConditionalOnJava()
// @ConditionalOnJndi
// public DateFormat dateFormat(){
// return DateFormat.getDateInstance();
// }
}
application.yml:
perry:
demo:
mytest: ball
标签:perry,SpringBoot,demo,Conditional,Bean,MyService,详解,MyConfig,注解
From: https://www.cnblogs.com/perry666/p/17793086.html