在日常开发中,存在着这种一种场景,框架对接口A提供了一个种默认的实现AImpl,随着需求的变更,现今AImpl不能满足了功能需要,这时,我们该怎么办? 当然是修改AImpl的实现代码了,但是,如果它是第三方依赖呢? 或者说,我们自己写了的某个功能模块,AImpl是我们为此模块提供的一种默认实现,用户可以使用它,也可以按需求进行覆盖(或者说是扩展),该怎么办?
对此,spring为我们提供了@Conditional注解,使用它可以很好的解决此类问题。
下面,举个例子。 有个RandomGenerator接口,接口里面有个generator()方法生成随机字符串,有两个实现类StringRandomGenerator和NumberRandomGenerator, 其中StringRandomGenerator是默认实现。也就是说,在我们不配置NumberRandomGenerator时,程序使用StringRandomGenerator生成随机字符串,在我们有配置NumberRandomGenerator时,程序使用NumberRandomGenerator生成随机字符串。
/** * 生成随机字符串的顶层接口 */ public interface RandomGenerator { Object generator(); }
import org.apache.commons.lang.RandomStringUtils; public class StringRandomGenerator implements RandomGenerator { @Override public Object generator() { char[] chars = {'a','b','c','d','e','f','g'}; String random = RandomStringUtils.random(5, chars); return "StringRandomGenerator:"+random; } }
/** * 将NumberRandomGenerator 注册成spring bean时,StringRandomGenerator 失效 * 相当于是NumberRandomGenerator中的generator方法覆盖了 StringRandomGenerator 中的generator方法 */ @Component public class NumberRandomGenerator implements RandomGenerator { @Override public Object generator() { String random = RandomStringUtils.random(5, true, true); return "NumberRandomGenerator:" + random; } }
/** * 配置类 */ @SpringBootConfiguration public class RandomGeneratorConfig { /** * @ConditionalOnMissingBean(value = RandomGenerator.class) * 该注解的意思是: 如果Ioc容器中没有 RandomGenerator 类型的 bean时 * 就将StringRandomGenerator注册到Ioc容器中 */ @Bean @ConditionalOnMissingBean(value = RandomGenerator.class) public RandomGenerator stringRandomGenerator() { return new StringRandomGenerator(); } }
最后写个controller来测试一把
@RestController public class RandomController { @Autowired private RandomGenerator randomGenerator; @GetMapping("/random") public Object random() { return randomGenerator.generator(); } }
在将NumberRandomGenerator 注册到Ioc容器的情况下,测试结果如下:
接下来,我们将NumberRandomGenerator类上中@Component注解干掉,再测试
完美!