自定义注解
有时我们想根据自己的业务需求自定义条件注解,需要使用@Conditional + Condition
自定义条件类:
package com.lin.missyou.sample.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class DianaCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String name = context.getEnvironment().getProperty("hero.condition");
return "diana".equalsIgnoreCase(name);
}
}
package com.lin.missyou.sample.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class IreliaCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String name = context.getEnvironment().getProperty("hero.condition");
return "irelia".equalsIgnoreCase(name);
}
}
接口:
public interface ISkill {
void r();
}
实现类:
package com.lin.missyou.sample.hero;
import com.lin.missyou.sample.ISkill;
public class Diana implements ISkill {
public Diana() { System.out.println("Hello Diana"); }
public void r(){ System.out.println("Diana R"); }
}
package com.lin.missyou.sample.hero;
import com.lin.missyou.sample.ISkill;
public class Irelia implements ISkill {
public Irelia() { System.out.println("Hello Irelia"); }
public void r(){ System.out.println("Irelia R"); }
}
配置类:
package com.lin.missyou.sample;
import com.lin.missyou.sample.condition.DianaCondition;
import com.lin.missyou.sample.condition.IreliaCondition;
import com.lin.missyou.sample.hero.Diana;
import com.lin.missyou.sample.hero.Irelia;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HeroConfiguration {
@Bean
@Conditional(DianaCondition.class)
public ISkill diana(){
return new Diana();
}
@Bean
@Conditional(IreliaCondition.class)
public ISkill irelia(){
return new Irelia();
}
}
控制器:
package com.lin.missyou.api.v1;
import com.lin.missyou.sample.IConnected;
import com.lin.missyou.sample.ISkill;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/v1/banner")
public class BannerController {
@Autowired
private ISkill iSkill;
@GetMapping("/test")
public String test1() {
iSkill.r();
return "Hello test1";
}
}
当配置文件如下,启动应用,控制台打印出‘Hello Diana’,说明Diana这个类被加入到容器。
hero.condition = diana

访问接口,控制台打印出‘Diana R’

当配置文件中的值改为‘irelia’,启动应用,控制台打印出‘Hello Irelia’,说明Irelia这个类被加入到容器。
hero.condition = irelia

访问接口,控制台打印出‘Irelia R’

内置的成品条件注解
| 注解 | 条件 |
|---|---|
| @ConditionalOnBean | 当SpringIoC容器内存在指定Bean的条件 |
| @ConditionalOnMissingBean | 当SpringIoC容器内不存在指定Bean的条件 |
| @ConditionalOnClass | 当SpringIoC容器内存在指定Class的条件 |
| @ConditionalOnMissingClass | 当SpringIoC容器内不存在指定Class的条件 |
| @ConditionalOnProperty | 指定的属性是否有指定的值 |
| @ConditionalOnResource | 类路径是否有指定的值 |
| @ConditionalOnWebApplication | 当前项目是Web项目的条件 |
| @ConditionalOnNotWebApplication | 当项目不是Web项目的条件 |
| @ConditionalOnExpression | 基于SpEL表达式作为判断条件 |
| @ConditionalOnJava | 基于JVM版本作为判断条件 |
| @ConditionalOnJndi | 在JNDI存在时查找指定的位置 |
| @ConditionalOnSingleCandidate | 当指定Bean在SpringIoC容器内只有一个,或者虽然有多个但是指定首选的Bean |
@ConditionalOnProperty
@ConditionalOnProperty几个主要参数:value指定配置文件中的key;havingValue用于指定这个key的值;matchIfMissing配置文件中没有找到对应的配置项。
将配置类改成如下形式,可以起到和上面一样的效果。@ConditionalOnProperty的参数 value指定配置文件中的key,havingValue用于指定这个key的值。
@Configuration
public class HeroConfiguration {
@Bean
@ConditionalOnProperty(value = "hero.condition",havingValue = "diana")
public ISkill diana(){
return new Diana();
}
@Bean
@ConditionalOnProperty(value = "hero.condition",havingValue = "irelia")
public ISkill irelia(){
return new Irelia();
}
}
当在@ConditionalOnProperty加一个参数(matchIfMissing = true),配置文件改为
hero.condition = irelia111
此时启动应用却发现报错了

当把配置文件中的配置项注释掉,就会把Diana注入到容器
#hero.condition = irelia

matchIfMissing并不是条件不成立,而是配置文件中没有找到对应的配置项,起到默认值的作用。
@ConditionalOnBean
当SpringIoC容器内存在指定Bean条件成立
当把配置类改为:
@Configuration
public class HeroConfiguration {
@Bean
@ConditionalOnBean(name="camille")
public ISkill diana(){
return new Diana();
}
}
并且在Camille上标注@Component,此时可以将Diana注入容器
@Component
public class Camille {
}

@ConditionalOnMissingBean
当SpringIoC容器内不存在指定Bean条件成立
配置类改为
@Configuration
public class HeroConfiguration {
@Bean
@ConditionalOnMissingBean(name="camille")
public ISkill diana(){
return new Diana();
}
}
此时Diana就不会被注入容器了
使用场景
@Conditional并不是只能在@Configuration配置类中使用,任何@Component及其衍生注解下面都可以追加条件注解。
以上这些条件注解在我们自己写业务时可能并不常用,通常在写一些第三方库时,实现了同一个接口可能有很多个Bean,为了保证实现一个接口的只有一个Bean就需要使用条件注解了。比如,当相同类型的Bean不存在时才注入当前的Bean,如果已经存在相同类型的Bean就不再注入,这种情况下就可以使用 @ConditionalOnMissingBean ;还有有时Bean与Bean之间存在依赖关系,就像上面的例子中BannerController依赖于ISkill接口,很多时候我们需要判断它所依赖的Bean是否存在,如果存在才把它注入容器,这种情况下就可以使用 @ConditionalOnBean
本文详细介绍了如何在Spring框架中使用自定义注解来实现基于条件的Bean注册,包括自定义条件注解的创建和使用,以及Spring提供的多种内置条件注解的应用场景。
721

被折叠的 条评论
为什么被折叠?



