SpringBoot @Condition 注解
简介
Conditional作用就是当你注册bean时,可以对这个bean添加一定的自定义条件,当满足这个条件时,注册这个bean,否则不注册。
开始
新建User.java
public class User {
}
新建一个UserConfig.java 用来注入bean。
@Configuration
public class UserConfig {
@Bean
public User userBean(){
return new User();
}
}
修改启动类,我们在启动的时候去获取userBean
@SpringBootApplication
public class BootConditionApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BootConditionApplication.class, args);
User user = (User) context.getBean("userBean");
System.out.println(user);
}
}
如果userBean在Spring容器里面,我们就可以通过上下文可以获取到user 对象.
在以上的代码中,我们是可以获取到bean哈,控制台打印结果如下所示:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.1.RELEASE)
2023-07-03 10:19:47.362 INFO 2580 --- [ main] x.b.condition.BootConditionApplication : Starting BootConditionApplication on ZJZL-20210402GJ with PID 2580 (F:\idea-project\xy-integration-middleware\boot\boot-condition\target\classes started by Administrator in F:\idea-project\xy-integration-middleware)
2023-07-03 10:19:47.391 INFO 2580 --- [ main] x.b.condition.BootConditionApplication : No active profile set, falling back to default profiles: default
2023-07-03 10:19:49.206 INFO 2580 --- [ main] x.b.condition.BootConditionApplication : Started BootConditionApplication in 3.789 seconds (JVM running for 10.207)
xy.boot.condition.entity.User@15bcf458
简单的场景实现
要求:我们要求userBean 在引入fastjson的情况下,才进行注入,反之不进行注入。
Conditional源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
可以看到value里面的值类型只定义了一个Class类型的数组 ,要求为Condition的泛型。
Condition接口
这个接口只定义了一个方法名为matches,返回值为一个boolean,这个时候我们不难猜出,
当Conditional注解中的值为true则会执行标注的方法,这里我们再写一个类实现Condition接口 ,
可以看到默认的返回值是为 false。
/**
ConditionContext:这个对象是个上下文对象,可以用它获取环境,ioc以及类加载器
AnnotatedtypeMetadata:注解元对象,可以获得注解中传入的值
*/
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}
通过以上代码,我们可以实现condition接口,实现自己自定义的方式。
自定义condition
public class ClassOnCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 定义一个布尔值
boolean flag;
try {
// 通过反射找到fastjson的类
Class<?> aClass = Class.forName("com.alibaba.fastjson.JSON");
// 找到了则返回true
flag = true;
} catch (ClassNotFoundException e) {
// 找不到则返回false
flag = false;
}
return flag;
}
}
在UserConfig.java 中加入Conditional注解,如下所示:
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassOnCondition.class)
public User user(){
return new User();
}
}
测试
未加入依赖
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.1.RELEASE)
2023-07-03 10:31:22.175 INFO 7724 --- [ main] x.b.condition.BootConditionApplication : Starting BootConditionApplication on ZJZL-20210402GJ with PID 7724 (F:\idea-project\xy-integration-middleware\boot\boot-condition\target\classes started by Administrator in F:\idea-project\xy-integration-middleware)
2023-07-03 10:31:22.193 INFO 7724 --- [ main] x.b.condition.BootConditionApplication : No active profile set, falling back to default profiles: default
2023-07-03 10:31:23.791 INFO 7724 --- [ main] x.b.condition.BootConditionApplication : Started BootConditionApplication in 2.88 seconds (JVM running for 6.428)
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userBean' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:772)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1221)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1083)
at xy.boot.condition.BootConditionApplication.main(BootConditionApplication.java:13)
Disconnected from the target VM, address: '127.0.0.1:63662', transport: 'socket'
加入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.1.RELEASE)
2023-07-03 10:33:00.091 INFO 15508 --- [ main] x.b.condition.BootConditionApplication : Starting BootConditionApplication on ZJZL-20210402GJ with PID 15508 (F:\idea-project\xy-integration-middleware\boot\boot-condition\target\classes started by Administrator in F:\idea-project\xy-integration-middleware)
2023-07-03 10:33:00.099 INFO 15508 --- [ main] x.b.condition.BootConditionApplication : No active profile set, falling back to default profiles: default
2023-07-03 10:33:01.458 INFO 15508 --- [ main] x.b.condition.BootConditionApplication : Started BootConditionApplication in 2.409 seconds (JVM running for 6.339)
xy.boot.condition.entity.User@60afd40d
Disconnected from the target VM, address: '127.0.0.1:63765', transport: 'socket'
优化
我们可以在自定义一个注解 ConditionalOnClass
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassOnCondition.class)
public @interface ConditionalOnClass {
String[] value();
}
修改ClassOnCondition
public class ClassOnCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 定义一个布尔值
boolean flag;
try {
// 通过注解名获取其中的值
Map<String, Object> map = annotatedTypeMetadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
// 获取value的值
String[] classNames = (String[]) map.get("value");
for (String className : classNames) {
Class<?> aClass = Class.forName(className);
}
flag = true;
} catch (ClassNotFoundException e) {
// 找不到则返回false
flag = false;
}
return flag;
}
}
修改UserConfig
@Configuration
public class UserConfig {
@Bean
@ConditionalOnClass("com.alibaba.fastjson.JSON")
public User user(){
return new User();
}
}
修改完成后,重新启动,我们会发现跟上面测试结果是一样子的。