spring注入bean的几种策略模式
上篇文章Spring IOC的核心机制:实例化与注入我们提到在有多个实现类的情况下,spring是如何选择特定的bean将其注入到代码片段中,我们讨论了按照名称注入和使用@Qualifier 注解输入的两种方式,本篇文章将结合之前提到的和spring的其他注入方式一起进行讨论。
本文主题
我们将讨论在一个接口或者抽象类在具有多个实现类的情况下,有多少种策略能够让我们在特定的代码片段中注入想要的bean。
按照名称
定义一个Skill借口,他描述了英雄具备哪些技能,现在有两个英雄的实现类Diana和Irelia,通过component注解将其标注为bean,在容器启动的时候会将他们加载到容器中。
现在有一个BannerController要使用Diana这个bean
@RestController public class BannerController { @Autowired private Skill diana; @RequestMapping(value = "/v2/banner", method = {RequestMethod.GET}) public String test() { diana.r(); return "Hello SpringBoot"; } }
private Skill diana;这里将成员变量的名字写成Diana这个bean的名字,容器就会选择Diana这个注入,这就叫做按照名称注入。spring会给每个bean设置默认到的名字也可以自定义,大家自行查找资料了解即可。
@Qualifier 注解
还是上文的例子,如果成员变量名不写成bean的名称,是其他的名字,比如按照常规的写法会写成
private Skill skill;这个时候就可以使用@Qualifier 注解,
@RestController public class BannerController { @Autowired @Qualifier("diana") private Skill skill; @RequestMapping(value = "/v2/banner", method = {RequestMethod.GET}) public String test() { skill.r(); return "Hello SpringBoot"; }
有选择的注入一个bean,注释掉某个bean上的@Component
如果我们确定要使用哪个bean,那可以把其他的注释掉
//@Component public class Irelia implements Skill { public Irelia() { System.out.println("Hello, Irelia"); } public void q(){ System.out.println("Irelia Q"); } public void w(){ System.out.println("Irelia W"); } public void e(){ System.out.println("Irelia E"); } public void r(){ System.out.println("Irelia R"); } }
让Skill的实现类只有一个,自然就不要再操心注入哪个了,就只会注入存在于容器当中的惟一的那一个了。
使用@Primary提高bean的优先级
还可以使用@Primary注解提高我们想让注入bean的优先级,那spring在扫描到相同类型的bean的时候,就会看谁的优先级高,谁高谁注入
@Component @Primary public class Diana implements Skill { private String skillName = "Diana R"; public Diana() { System.out.println("I am Diana"); } public void q(){ System.out.println("Diana Q"); } public void w(){ System.out.println("Diana W"); } public void e(){ System.out.println("Diana E"); } public void r(){ System.out.println(this.skillName); } }
然后启动启动程序,访问路由,就会看到下面的输出:
说明确实是注入了Diana这个bean。
阶段总结
上面的实现方式看起来都能实现按照所需注入特定的bean,但是有个问题,当发生变化的时候,这里的变化可能是英雄名变了,新增英雄或者要替换其他英雄,都需要去手动改代码,有些情况下可能还不只改一处,还是比较繁琐,并不方便。那有没有一种方式可以通过配置文件的形式来指定要注入的bean,当变化发生,只需要改配置,那岂不是很方便很灵活很开心。
条件注解
条件注解顾名思义,就是按照条件决定注入哪一个bean,所以要想使用条件注解,就得先写一个条件。
spring为我们提供了特定的方式来实现自己的条件:@Conditional注解+Condition接口,spring的这种方式的原理是把符合条件的bean加加载到容器中,不合的不加载,那这样在注入的时候就不会有多个相同类型的bean存在了,自然也就注入成功了。
定义一个类实现Condition接口
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class HeroCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return false; } }
实现Condition接口必须实现它的matches方法,我们先来解释一下这个方法的入参和返回值,
ConditionContext是一个接口,定义了他支持那些操作
public interface ConditionContext { BeanDefinitionRegistry getRegistry(); ConfigurableListableBeanFactory getBeanFactory(); Environment getEnvironment(); ResourceLoader getResourceLoader(); ClassLoader getClassLoader(); }
其中的getEnvironment方法会返回Environment对象,他里面会记录当前应用所有的环境信息,可以通过这个对象获取到我们的配置信息。
返回值是Boolean类型的,哪个bean的条件匹配成功,就会把这个bean注入到代码片段中去。我们来具体实现一下。
public class HeroCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { String name = context.getEnvironment().getProperty("hero.condition"); System.out.println(name); if ("diana".equalsIgnoreCase(name)){ return true; }else if ("irelia".equalsIgnoreCase(name)){ return true; } return false; } }
@Configuration public class HeroConfiguration { @Bean @Conditional(HeroCondition.class) public Skill diana(){ return new Diana(); } @Bean @Conditional(HeroCondition.class) public Skill irelia(){ return new Irelia(); } }
通过以上的方式,就可以完成一个简单的条件注解,但是这种需求其实spring boot早已经帮我们实现了,提供了一些注解可以使用,下篇文章我们看看使用spring boot的内置注解,如何来解决我们的问题。
博客地址:https://www.immortalp.com/
欢迎大家去 我的博客 瞅瞅,里面有更多关于测试实战的内容哦!!
- spring bean 日期格式注入的几种模式
- spring的注入bean的几种方式
- spring几种依赖注入方式以及ref-local/bean,factory-bean,factory-method区别联系
- spring自动注入接口的多个实现类(结合策略设计模式)
- Spring学习笔记二(Bean注入的几种方式)
- Strategy 策略模式 在 Spring 开发中的应用 包括事务管理,日志管理(logger),IoC容器根据bean定义的内容实例化等
- 实例注入Bean的几种形式,特别注意多例模式下Bean生命周期无人管理
- Spring学习笔记二(Bean注入的几种方式)
- Spring中bean属性注入的几种方式
- spring bean 注入失败的几种原因
- Spring学习(五)-----注入bean属性的三种方式( 1: 正常的方式 2: 快捷方式 3: “p” 模式)
- spring注入时bean的set方法为什么不能是static类型的?(为什么要用单例模式而不是静态方法)
- Spring注入Bean的几种方式
- spring bean单例注入与用单例模式通过class.getinstance()区别?
- Spring逐点击破(一)—依赖(Bean)注入的几种方式(全)
- Spring Bean装配--@Bean注解注入说明
- 【Spring】 注入 Bean 到 List / Map 中
- spring 注入bean的三种方式
- 如何让servelt和Filter注入到spring容器或者在servlet中调用spring中的bean
- 从“假如有以下几种价格10,20,50,请你代码实现将他们排序输出”看设计模式中的策略模式