Spring配置文件结构对于生成Bean的影响

有段时间忙于毕设,导致Spring学习的东西忘了很多,所以最近又开始从头看Spring的基础。基础的Bean的装配不再多说了。这一次,主要是深入一点了解Spring配置文件结构搭配对于Bean装配的影响。

首先,我们设定一个简单的场景:播放器播放歌曲。所以基于此,我们定义两个接口:

package demo;
// CD接口
public interface CompactDisc {
void play();
}
package demo;
// 媒体播放器接口
public interface MediaPlayer {
void play();
}

按照是实际来讲,我们定义一个BlankDisc,空白的唱片,其包含三个属性:title、artist和tracks,分别代表了唱片的标题、歌手以及歌曲目录:

package demo.cd;

import demo.CompactDisc;
import java.util.List; public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks; // 简化结构,只存放歌曲目录名称并保存为List
public BlankDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
@Override
public void play() {
System.out.println("Playing " + title + " \n\tby " + artist);
tracks.stream().forEach(t -> System.out.println(" \t>>> " + t));
}
}

同样的,实现MediaPlayer接口,定义实际的唱片播放器,能够持有cd的引用,同时,这里我们并没有通过构造器来定义,原因是唱片播放器并非一定放有cd(当然代码没有对null进行约束,这是不好的,实际编写请勿这样编写):

package demo.player;

import demo.CompactDisc;
import demo.MediaPlayer; public class CDPlayer implements MediaPlayer {
private CompactDisc cd; public void setCd(CompactDisc cd) {
this.cd = cd;
}
@Override
public void play() {
System.out.println("CDPlayer 开始播放: ");
cd.play();
}
}

接下来,要说明的是,Spring支持xml与Java文件同时存在的配置方式,这里我们也会这么做,尽可能的复杂化配置依赖,因为本片文章就是探讨各种配置文件交叉依赖的情形,并理清依赖的思路。

首先我们将CD类Bean与CDPlayer类Bean分离开来。

首先是CD类Bean

Java类型配置文件
package demo.config;

import demo.cd.BlankDisc;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.ArrayList;
import java.util.List; @Configuration
public class CDConfig {
@Bean
public BlankDisc yeHuiMei() {
List<String> tracks = new ArrayList<>();
tracks.add("以父之名");
tracks.add("懦夫");
tracks.add("晴天");
tracks.add("...");
return new BlankDisc("YeHuiMei", "JayChou", tracks);
}
}

在这个配置文件中,只定义了一个Bean,Bean id名称为yeHuiMei(方法名),同时也将相关的属性设置完毕。

xml类型配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="onTheRun"
class="demo.cd.BlankDisc">
<constructor-arg name="title" value="On The Run"/>
<constructor-arg name="artist" value="JayChou"/>
<constructor-arg name="tracks">
<list>
<value>牛仔很忙</value>
<value>彩虹</value>
<value>青花瓷</value>
<value>...</value>
</list>
</constructor-arg>
</bean>
</beans>

在这个xml配置文件中,我定义了一个名为onTheRun的Bean,同时也设置了对应的属性。

CDPlayer的Bean

Java类型配置文件
@Configuration
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayerInJava(@Qualifier("onTheRun") CompactDisc cd) {
CDPlayer cdPlayer = new CDPlayer();
cdPlayer.setCd(cd);
return cdPlayer;
}
}
xml类型配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cdPlayerInXML" class="demo.player.CDPlayer">
<property name="cd" ref="yeHuiMei"/>
</bean>
</beans>

目前配置文件搞定了,并且我们现在的配置以来结构如下:

当然,目前还是有一定的问题的,因为很显然,我们的配置文件都独立与彼此。尽管在CDPlayer中的配置文件通过相关的语法制定了CD Bean的选择(@Qualifier和ref),但是我们可以看到文件本身并没有明确的引入另外的配置文件,所以在IDEA中通常会有这样的提示:





同时打开,IDEA的项目结构Project Structs(win默认ctrl+shift+alt+s),点击左侧的Modules,可以看到Spring项目上右下角IDEA提示我们“Unmapped Spring configuration files”并列举除了上述的四个文件。

我们点击上面的+将所有的配置文件追踪上,刚刚所有的索引问题都OK了。此时,我们任意找到一个xml文件,可以看到左上方有一个小标志,点击并选择第一个:



打开之后就能够看到整个项目对于配置文件的依赖:



可以看到我们的项目(springdemo)具有一个是上下文应用模块,这个应用上下文包含了四份配置文件。但一定要注意,在后续我们加载配置文件的时候,必须要将有依赖关系的配置文件全部加载进来才能够读取到对应的Bean。这里我们进行一个简单的测试:

@RunWith(SpringJUnit4ClassRunner.class)
// 设置所要加载的配置文件
@ContextConfiguration(locations = {"classpath:cdconfig.xml"})
public class CDPlayerTest {
@Autowired
@Qualifier("onTheRun")
private CompactDisc cd; @Test
public void cdShouldNotNull() {
cd.play();
assertNotNull(cd);
}
}

这个测试是可以直接通过的,因为这里我们加载的是cdconfig.xml配置文件,里面我们定义了名为onTheRun的Bean,所以打印还有非空测试也通过:



然而接下来我们更换配置文件为cdplayerconfig.xml,相关注入如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:cdplayerconfig.xml"})
public class CDPlayerTest {
@Autowired
@Qualifier("cdPlayerInXML")
private MediaPlayer mp;
@Test
public void mediaPlayerNotNull() {
System.out.println(mp);
mp.play();
assertNotNull(mp);
}
}

这里我们指定注入的就是xml中的CDPlayer Bean,然而,并不能通过测试,在错误提示中,我们可以找到这样一行:

Cannot resolve reference to bean 'yeHuiMei' while setting bean property 'cd'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'yeHuiMei' is defined
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)

前面我们知道,cdPlayerInXML这个bean中我们还注入了Java配置文件下的名为yeHuiMei Bean,而在测试的过程中,我们只加载了cdplayerconfig.xml这个配置文件。所以实际上除了这个配置文件意外的其他bean都没有被Spring生成并放入Bean容器中。

也许会有疑问,在上面的Bean依赖图中,我们看到所有的配置文件都有已经被放入到了Spring Application Context中,为什么不被自动加载呢?道理很简单,这只是IDE的辅助而已。IDEA中的那个部分只是IDEA自身的一些辅助功能比如静态检查,所以需要我们手动的将这些文件给添加进去。当我们还是移除掉刚刚的结构之后,进行第一次的只对没有依赖的CDBean进行测试依然有效。

一定要明确,Spring的注入是发生在代码中的!不要被IDE遮蔽了双眼!这里何时会被注入呢?当我们配置了Spring的配置文件并将其加载进来了,当Spring遇到@Autowired等注入注解的时候,就会为我们注入Bean。

通常,当我们有多个配置文件的是,最优的结构思路是将多个配置文件导入到一个专门的独立的配置文件中,就像下面这样,我将开始的四个配置文件全部导入到一个名为AllConfig的Java配置文件:

@Configuration
@Import({CDConfig.class, CDPlayerConfig.class})
// 一定要注意!!!classpath:后面一定不要带空格!否则会被识别为【[空格]cdconfig.xml】这样的文件名而不被找到,血的教训。
@ImportResource({"classpath:cdconfig.xml", "classpath:cdplayerconfig.xml"})
public class AllConfig {
}

然后在测试文件中我们将加载配置文件为Java配置文件AllConfig,此时,所有的以来问题全部解决:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AllConfig.class})
public class CDPlayerTest { @Autowired
@Qualifier("onTheRun")
private CompactDisc cd; @Test
public void cdShouldNotNull() {
cd.play();
assertNotNull(cd);
}
@Autowired
@Qualifier("cdPlayerInXML")// 一开始由于配置文件没有引入全导致注入失败
private MediaPlayer mp;
@Test
public void mediaPlayerNotNull() {
System.out.println(mp);
mp.play();
assertNotNull(mp);
}
}

Spring配置文件结构对于生成Bean的影响的更多相关文章

  1. Spring 01: Spring配置 + IOC控制反转 + Setter注入

    简介 Spring框架是一个容器,是整合其他框架的框架 他的核心是IOC(控制反转)和AOP(面向切面编程),由20多个模块构成,在很多领域都提供了优秀的问题解决方案 特点 轻量级:由20多个模块构成 ...

  2. Spring配置方式

    Spring配置方式 第一阶段:xml配置     在spring 1.x时代,使用spring开发满眼都是xml配置的bean,随着项目的扩大, 我们需要把xml配置文件分放到不同的配置文件中,那时 ...

  3. 让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean

    让Spring Boot项目启动时可以根据自定义配置决定初始化哪些Bean 问题描述 实现思路 思路一 [不符合要求] 思路二[满足要求] 思路三[未试验] 问题描述 目前我工作环境下,后端主要的框架 ...

  4. Spring源码解析 – @Configuration配置类及注解Bean的解析

    在分析Spring 容器创建过程时,我们知道容器默认会加载一些后置处理器PostPRocessor,以AnnotationConfigApplicationContext为例,在构造函数中初始化rea ...

  5. 使用spring配置类代替xml配置文件注册bean类

    spring配置类,即在类上加@Configuration注解,使用这种配置类来注册bean,效果与xml文件是完全一样的,只是创建springIOC容器的方式不同: //通过xml文件创建sprin ...

  6. Spring学习(六)bean装配详解之 【通过注解装配 Bean】【基础配置方式】

    通过注解装配 Bean 1.前言 优势 1.可以减少 XML 的配置,当配置项多的时候,XML配置过多会导致项目臃肿难以维护 2.功能更加强大,既能实现 XML 的功能,也提供了自动装配的功能,采用了 ...

  7. spring 配置bean

    Main(测试方法) public class Main { public static void main(String[] args) { //1.创建Spring 的IOC容器对象: //spr ...

  8. Spring @Service生成bean名称的规则

    今天碰到一个问题,写了一个@Service的bean,类名大致为:BKYInfoServcie.java dubbo export服务的配置: <dubbo:service interface= ...

  9. 解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException

    解决spring配置中的bean类型的问题:BeanNotOfRequiredTypeException这个问题出现的原因:一般在使用annotation的方式注入spring的bean 出现的,具体 ...

随机推荐

  1. 刷题-力扣-63. 不同路径 II

    63. 不同路径 II 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/unique-paths-ii/ 著作权归领扣网络所有.商业转 ...

  2. 《网页布局基础篇》HTML+CSS单列布局--水平居中,垂直居中,水平垂直居中

    https://blog.csdn.net/panlu666_pl/article/details/66480433 一.水平居中 子元素在父元素中水平居中 1.使用 text-align和inlin ...

  3. 文件权限的管理以及acl权限列表

    ls -l? 文件名称 上面的命令以长格式显示文件与目录,每一行都是一个文件或目录的属性数据,每个文件或子目录的属性数据又以7个字段显示,各个字段的说明如下: (1)文件类型与权限:该字段共有10个字 ...

  4. PyQT5:信号和槽

    PyQT5:信号和槽 信号和槽 Qt的主要特征之一是它使用信号和插槽在对象之间进行通信. 当潜在的事件发生时,会发出一个信号.插槽是可调用的Python,如果将信号连接到插槽,则在发出信号时将调用该插 ...

  5. 痞子衡嵌入式:MCUXpresso IDE下工程链接文件配置管理与自动生成机制

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下工程链接文件配置管理与自动生成机制. 痞子衡在 2018 年初写过一个专题 <嵌入式开发文件系列&g ...

  6. 图神经网络-环境配置与PyG库

    环境配置与PyG中图与图数据集的表示和使用 一.引言 PyTorch Geometric (PyG)是面向几何深度学习的PyTorch的扩展库,几何深度学习指的是应用于图和其他不规则.非结构化数据的深 ...

  7. noip模拟37

    \(\color{white}{\mathbb{燕子来时青尚在,木荫遥看杏花菲,名之以:杏红}}\) 考场发现 \(t2\) 基本上是原题,\(t3\) 的套路见过,\(t4\) 像是并查集之类的算法 ...

  8. vue-cli坑比系列

    Error loading saved preferences: ~/.vuerc may be corrupted or have syntax errors. Please fix/delete ...

  9. Mysql 面试宝典

    实时更新 你用过哪些数据库? mysql redis mysql 和 redis 的区别? 比较点 Mysql Redis 数据库类型 关系型 非关系型 作用 持久化层 存储需要持久化的数据,数据存在 ...

  10. 大数据最后一公里——2021年五大开源数据可视化BI方案对比

    个人非常喜欢这种说法,最后一公里不是说目标全部达成,而是把整个路程从头到尾走了一遍. 大数据在经过前几年的野蛮生长以后,开始与数据中台的概念一同向着更实际的方向落地.有人问,数据可视化是不是等同于数据 ...