前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站点击跳转浏览。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class extends Condition>[] value();
}
从代码中可以看到,需要传入一个Class数组,并且需要继承Condition接口:
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Condition是个接口,需要实现matches方法,返回true则注入bean,false则不注入。
用法如下
下面举例测试Condition的注入Bean
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dog {
private String name;
private String gender;
}
重写matches方法, 返回true则注入bean,false则不注入
如果容器中注入了 dog 就返回true
public class MyCondition implements Condition {
/**
* 重写matches方法, 返回true则注入bean,false则不注入。
* */
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 如果容器中注入了 dog 就返回true
if(beanFactory.containsBean("dog")){
return true;
}
return false;
}
}
@Configuration
public class MyConfig {
@Bean("dog")
//@ConditionalOnBean(name = {"dog2"})
public Dog dog1(){
return new Dog("金毛","公");
}
@Bean("dog1")
@Conditional(value = MyCondition.class)
public Dog dog2(){
return new Dog("拉布拉多","母");
}
}
AnnotationConfigApplicationContext是一个独立的应用上下文,它接受带注释的类作为输入。
例如@Configuration或@Component。 可以使用scan()查找 Bean,也可以使用register()注册 Bean。
public class tets {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Map beansOfType = applicationContext.getBeansOfType(Dog.class);
System.out.println(beansOfType);
}
}
测试结果如下
如果将MyCondition类中逻辑改为,如果如果容器中之前注入了 dog 就返回false,不注入其他的,
即:
public class MyCondition implements Condition {
/**
* 重写matches方法, 返回true则注入bean,false则不注入。
* */
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 如果容器中之前注入了 dog 就返回false
if(beanFactory.containsBean("dog")){
return false;
}
return true;
}
}
那么结果如下:
@Conditional本身还是一个父注解,派生出大量的子注解,如下:
@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:基于SpEL表达式的条件判断。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。
修改之前的配置类如下
@Configuration
public class MyConfig {
@Bean("dog")
public Dog dog1(){
return new Dog("金毛","公");
}
@Bean("dog1")
@ConditionalOnBean(name = {"dog"})// spring容器中有dog这个Bean 才会创建dog1
// @ConditionalOnMissingBean(name = {"dog"})// spring容器中不存在 dog这个Bean 才会创建dog1
public Dog dog2(){
return new Dog("拉布拉多","母");
}
}
结果如下:
然后再将第二个注释放开,第一个注释注释掉
结果如下: