Spring学习之旅(四)--高级装配Bean
条件化 bean
有时候我们要满足某种情况才将bean 初始化放入容器中。
基于环境初始化不同的 bean
1.申明接口并创建两个实现类
public interface Teacher {
void startWorking();
}
public class JavaTeacher implements Teacher {
public void startWorking() {
System.out.println("开始 Java 教学");
}
}
public class SqlTeacher implements Teacher {
public void startWorking() {
System.out.println("开始 SQL 教学");
}
}
2.JavaConfig 显式装配两个实现类
@Configuration
public class ApplicationConfig {
@Bean(name = "teacher")
@Profile("Monday")
public Teacher sqlTeacher() {
return new SqlTeacher();
}
@Bean(name = "teacher")
@Profile("Tuesday")
public Teacher javaTeacher() {
return new JavaTeacher();
}
}
注:可以看到两个 bean 都取名为 teacher,但是 @Profile 值不同。
3.单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@ActiveProfiles("Monday")
//@ActiveProfiles("Tuesday")
public class ConditionTest {
@Autowired(required = false)
private Teacher teacher;
@Test
public void test01(){
if(teacher != null){
teacher.startWorking();
}
}
}
执行单元测试,查看控制台输出:
开始 SQL 教学
通过 @ActiveProfiles 配置当前的环境,我们就能做到 周一 SQL教学 周二 Java 教学 了。
激活 Profile 方式
Spring 激活 Profile 依赖两个属性:
- spring.profiles.active
- spring.profiles.default
active 优先级比 default 高,如果两个属性都没有设置的话,将只会创建没有定义 profile 的 bean
除了 @ActiveProfiles 配置外,我们还能通过很多种方式来设置属性:
- 作为 DispatcherServlet 的初始化参数;
- 作为 Web 应用的上下文参数;
- 作为 JNDI 条目;
- 作为环境变量;
- 作为 JVM 的系统属性;
自定义提交
除了环境之外,我们也可以自定义条件来决定初始化那个 Bean。
例如刚刚的实例,老师开始 Java教学 ,除了时间是周二之外还应该有学生在,才能完成教学。
@Configuration
public class ApplicationConfig {
@Bean(name = "teacher")
@Conditional(MyCondition.class)
public Teacher javaTeacher() {
return new JavaTeacher();
}
}
通过 @Conditional 注解来自定义条件,MyCondition 是我们实现 Condition 接口完成的自定义条件判断
public class MyCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
// 1.获取属性值
List activeProfiles = Arrays.asList(environment.getActiveProfiles());
List defaultProfiles = Arrays.asList(environment.getDefaultProfiles());
// 2.判断属性是否存在
boolean activeFlag = activeProfiles.contains("Tuesday") && activeProfiles.contains("students");
boolean defaultFlag = defaultProfiles.contains("Tuesday") && defaultProfiles.contains("students");
return activeFlag || defaultFlag;
}
}
单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@ActiveProfiles({"Tuesday","students"})
public class ConditionTest {
@Autowired(required = false)
private Teacher teacher;
@Test
public void test01(){
if(teacher!=null){
teacher.startWorking();
}
}
}
控制台输出:
开始 Java 教学
ConditionContext 方法
public interface ConditionContext {
BeanDefinitionRegistry getRegistry();
ConfigurableListableBeanFactory getBeanFactory();
Environment getEnvironment();
ResourceLoader getResourceLoader();
ClassLoader getClassLoader();
}
- getRegistry():返回 BeanDefinitionRegistry 检查 bean 定义;
- getBeanFactory():返回 ConfigurableListableBeanFactory 检查 bean 是否存在和它的属性;
- getEnvironment():返回 Environment 检查环境变量是否存在以及它的值;
- getResourceLoader():返回 ResourceLoader 所加载的资源;
- getClassLoader():返回 ClassLoader 加载并检查类是否存在
处理自动装配歧义性
在之前我们讲到自动装配如果匹配到多个 bean 的话,Spring 会抛出一个 NoUniqueBeanDefinitionException 异常,表示没有明确指明使用哪个 bean 来进行自动装配。
标识首选 bean
通过 @Primart 注解可以将一个 bean 设置为首选,但是要注意的是,如果出现多个 @Primart 也还是会抛出异常。
限定自动装配的 bean
@Primart 注解不能将可选范围缩小到唯一一个无歧义的选项中。我们可以通过限定符的形式进行范围的缩小,直到唯一为止。
@Qualifier 注解是使用限定符的主要方式。它可以与 @Autowired 注解协同使用,在注入 bean 的时候指定注入的是那个 bean。
public interface Teacher {
void startWorking();
}
@Component
public class SqlTeacher implements Teacher {
public void startWorking() {
System.out.println("开始 SQL 教学");
}
}
@Component
public class JavaTeacher implements Teacher {
public void startWorking() {
System.out.println("开始 Java 教学");
}
}
@Autowired
@Qualifier("javaTeacher")
private Teacher teacher;
@Test
public void test01() {
teacher.startWorking();
}
@Qualifier 注解的参数就是想要注入的 bean 的 id。如果 @Component 没有显示指定 bean 的 Id ,那么默认的 Id 是类型首字母小写。这跟类名就有耦合性了,我们可以在类上加 @Qualifier(name) 的形式设置别名避免和类名耦合。
自定义限定符
要注意的是 @Qualifier 也可能出现重复,我们可以通过增加多个条件来进一步缩小范围,但是 Java 不支持在同一个条目上出现相同类型的多个注解,我们可以通过自定义注解的形式来解决这个问题。
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Monday {
}
我们定义了一个 Monday 注解,我们来使用一下它:
@Component
@Monday
public class JavaTeacher implements Teacher {
public void startWorking() {
System.out.println("开始 Java 教学");
}
}
使用:
@Autowired
@Monday
private Teacher teacher;
bean 作用域
默认情况下 Spring 应用上下文中的所有 bean 都是以单例形式注入,但是在某些情况下可能就不太适用。比如购物车组件这种有状态值的,针对每一个用户应该是不同的实例。
Spring 定义了多种作用域:
- 单例(Singleton): 在整个应用中,只创建 bean 的一个实例;
- 原型(Prototype):在每次注入或者通过 Spring 应用上下文获取的时候,都会创建一个实例;
- 会话(Session):在 Web 应用中,为每个会话创建一个 bean 的实例;
- 请求(Rquest):在 Web 应用中,为每一个请求创建一个 bean 的实例。
如何指定作用域
通过使用 @Scope 注解或 scope标签 可以配置作用域。
运行时注入属性
Spring 提供了两种在运行时赋值的方式:
- 属性占位符(Property plaveholder)
- Spring 表达式语言(SpEL)
它们都可以在应用运行时在获取值,避免硬编码的存在。
Spring学习之旅(四)--高级装配Bean的更多相关文章
- Spring第一课:基于XML装配bean(四),三种实例化方式:默认构造、静态工厂、实例工厂
Spring中基于XML中的装配bean有三种方式: 1.默认构造 2.静态工厂 3.实例工厂 1.默认构造 在我们在Spring的xml文件中直接通过: <bean id=" ...
- Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探
由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...
- Spring入门(5)-自动装配Bean属性
Spring入门(5)-自动装配Bean属性 本文介绍如何装配Bean属性. 0. 目录 ByName ByType constructor 默认自动装配 混合使用自动装配和显示装配 1. ByNam ...
- Spring学习之旅(十)--MockMvc
在之前的 Spring学习之旅(八)--SpringMVC请求参数 我们是通过在控制台输出来验证参数是否正确,但是这样做实在是太耗时间了,我们今天来学习下 MockMvc,它可以让我们不需要启动项目就 ...
- Spring学习之旅(三)--装配Bean
装配 Bean 的方式 在 XML 中进行显式配置 在 Java 中进行显式配置 隐式的 Bean 发现机制和自动装配 Spring 提供了以上三种方式进行 Bean 的配置,可以根据自己的需求选择一 ...
- Spring高级装配bean
目录 spring profile 条件化的bean声明 自动装配与歧义性 bean的作用域 Spring表达式语言 一.环境与profile 配置profile bean 在软件开发的时候,有一个 ...
- Spring学习之旅(四)Spring工作原理再探
上篇博文对Spring的工作原理做了个大概的介绍,想看的同学请出门左转.今天详细说几点. (一)Spring IoC容器及其实例化与使用 Spring IoC容器负责Bean的实例化.配置和组装工作有 ...
- spring使用之旅(一) ---- bean的装配
基础配置 启用组件扫描配置 Java类配置文件方式 package com.springapp.mvc.application; import ...
- spring学习笔记(四)我对spring中bean生命周期的理解
我相信大部分同学对spring中bean的生命周期都不陌生,但是如果要详细的说出每一个步骤,可能能说出来的也不多,我之前也是这样,前几天调了一下spring的源码,看了一点书,突然一下明朗了,理解了s ...
随机推荐
- LiteDB源码解析系列(2)数据库页详解
在这一篇里,我将用图文的方式展示LiteDB中页的结构及作用,内容都是原创,在描述的过程中有不准确的地方烦请指出. 1.LiteDB页的技术工作原理 LiteDB虽然是单个文件类型的数据库,但是数据库 ...
- 【原创】这一次,Chrome表现和IE11一样令人失望,围观群众有:Edge,Firefox
前言 俗话说,常在河边走哪能不湿鞋,天天和浏览器打交道,发现浏览器竟然也隐藏BUG也不是新鲜事了.可以看下我之前的文章: [原创]分享IE7一个神奇的BUG(不是封闭标签的问题,的确是IE7的BUG) ...
- spring 事务隔离级别导致的bug
事情是这样的,ios进货单有一个数量加一手,减一手的功能,每加减一次就会异步调用后台的接口,后台判断sku如果不存在就插入,存在就更新. 问题描述: 当ios发了多次请求后, 在第二次请求的时候, ...
- C++多小球非对心弹性碰撞(HGE引擎)
程序是一个月前完成的,之前一直没正儿八经的来整理下这个程序,感觉比较简单,不过即使简单的东西也要跟大家分享下. 源码下载:http://download.csdn.net/detail/y851716 ...
- Linux下安装配置Jmeter5.1,并执行jmx文件
Windows下的jmeter是GUI模式,可查看操作,但是GUI对性能的干扰比较大,所有一般压测会在Linux上运行. 下面是Linux下安装配置Jmeter5.1,并执行jmx文件的步骤, 一.安 ...
- 理解SVG中的 viewport,viewBox, preserveAspectRatio
_ 阅读目录 一:理解viewport 二:理解viewBox 三:理解 preserveAspectRatio 回到顶部 一:理解viewport 该属性表示的是SVG可见区域的大小.或者也可以叫画 ...
- .net core开发从未如此简单,比abp更接地气
在谈起java一家独大的时候,dotnet人员总是一边嘲笑大量滥竽充数的java从业者,一边羡慕人家的生态.以前是只能羡慕,现在dotnet core开源了,我们都可以为dotnet core的开原生 ...
- codeforces 371 C-Hamburgers
一个乱七八糟的故事背景,可以练练英语阅读. 大概的意思是Polycarpus喜欢汉堡,现在他有你ns片香肠片,nb面包,nc块起司,有r卢布,每种东西都有价格,如果不够他可以去商店买(商店里面各种东西 ...
- UE4中UMG与C++交互 页面文本修改
在UE4中,有两种方式创建ui,一种是使用slate的方式,一种是UMG,UMG是slate的封装,是一个可视化的ui编辑器.slate则是纯c++方式(之前实验过一次slate创建页面,代码相当麻烦 ...
- Struts完成用户新增操作
点击新增客户出现该页面并完成前后台交互 代码逻辑分析: jsp 页面部分代码 <TABLE id=table_1 style="DISPLAY: none" cellSpac ...