前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Spring配置文件结构对于生成Bean的影响

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

作者头像
w4ngzhen
发布于 2023-10-16 13:38:27
发布于 2023-10-16 13:38:27
12300
代码可运行
举报
文章被收录于专栏:编译思想编译思想
运行总次数:0
代码可运行

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

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package demo;
// CD接口
public interface CompactDisc {
    void play();
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package demo;
// 媒体播放器接口
public interface MediaPlayer {
    void play();
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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进行约束,这是不好的,实际编写请勿这样编写):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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类型配置文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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类型配置文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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类型配置文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class CDPlayerConfig {
    @Bean
    public CDPlayer cdPlayerInJava(@Qualifier("onTheRun") CompactDisc cd) {
        CDPlayer cdPlayer = new CDPlayer();
        cdPlayer.setCd(cd);
        return cdPlayer;
    }
}
xml类型配置文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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。这里我们进行一个简单的测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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,相关注入如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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,然而,并不能通过测试,在错误提示中,我们可以找到这样一行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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配置文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
@Import({CDConfig.class, CDPlayerConfig.class})
// 一定要注意!!!classpath:后面一定不要带空格!否则会被识别为【[空格]cdconfig.xml】这样的文件名而不被找到,血的教训。
@ImportResource({"classpath:cdconfig.xml", "classpath:cdplayerconfig.xml"})
public class AllConfig {
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-022,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring-2.装配
通过@Configuration租借表明类是配置类,该类应该包含在Spring应用上下文中如何创建bean的细节。 注意和上一节相比,移除了@ComponentScan注解。
悠扬前奏
2019/05/30
6420
Spring实战——XML和JavaConfig的混合配置
前言 看了园龄已经两年多了,再不能写完内容直接点击发布,留下一片密密麻麻的文字让别人看的头昏脑涨。所以现在每次写完主要内容后,还需要对于格式稍稍调整下。那么有没有什么编辑模式能够在你写完文章后基本也把格式调的八九不离十,不会辣眼睛呢,当然有,那就是Markdown。 本篇就在Markdown编辑环境下说说Spring的导入和混合配置 上篇提到了关于Spring的显示配置方式有两种,一种是基于XML配置,一种是基于JavaConfig的方式配置。对于这两种配置方式并不是互斥关系,相反,他们两能够相互融合,有
JackieZheng
2018/01/16
1.3K0
Spring实战——XML和JavaConfig的混合配置
Spring实战2:装配bean—依赖注入的本质主要内容
任何一个成功的应用都是由多个为了实现某个业务目标而相互协作的组件构成的,这些组件必须相互了解、能够相互协作完成工作。例如,在一个在线购物系统中,订单管理组件需要与产品管理组件以及信用卡认证组件协作;这些组件还需要跟数据库组件协作从而进行数据库读写操作。
阿杜
2018/08/06
7070
Spring_总结_03_装配Bean(三)之XML配置
用来装配bean的最基本的XML元素包含在spring-beans模式中,在上面这个XML文件中,它被定义为根命名空间。
shirayner
2018/08/10
2080
Spring4实战学习笔记
《Spring4实战 第4版》2016年4月新出版的,之前的第三版看起来还是不错的,所以看到新版就直接买下来。
Java架构师必看
2020/04/22
8130
Spring实战——无需一行xml配置实现自动化注入
  已经想不起来上一次买技术相关的书是什么时候了,一直以来都习惯性的下载一份电子档看看。显然,如果不是基于强烈的需求或强大的动力鞭策下,大部分的书籍也都只是蜻蜓点水,浮光掠影。   就像有位同事说的一样,有些书没有真真切切的经历过,你去看,看了就是看了,只是没有留下多少印象。我回头仔细想了想,大概就是这样,好比你去看设计模式相关的书籍,了解到了适配器模式,但是还是不够深刻。比如说某天你去面试的时候别人会问你,"你了解过适配器模式么,你有过这个模式的开发经历么,你能否画出你使用适配器模式的UML图..." 如
JackieZheng
2018/01/16
7850
Spring实战——无需一行xml配置实现自动化注入
Spring超详细总结
Spring竭力避免因自身的API而弄乱你的应用代码。Spring不会强迫你实现Spring规范的接口或继承Spring规范的类,相反,在基于Spring构建的应用中,它的类通常没有任何痕迹表明你使用了Spring。最坏的场景是,一个类或许会使用Spring注解,但它依旧是POJO
说故事的五公子
2020/02/12
7340
Spring------自动化装配Bean(一) 一、创建 CompactDisc接口和SgetPeppers实现类二、启用spring组件扫描三、编写测试类,并运行 四、补充说明
  CompactDisc接口方法为播放。SgtPeppers实现CompactDisc接口。
用户2417870
2019/09/18
4970
Spring bean注解配置(2)—— @Autowired
@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。系统自动为你注入,即隐式配置。自动装配的意思就是:找到合适的Bean注入给这个注释变量。
浩Coding
2019/07/03
1.4K0
Spring基础知识之装配Bean
    1)组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
用户1134788
2022/05/09
2020
Spring_总结_03_装配Bean(四)之导入与混合配置
在典型的Spring应用中,我们可能会同时使用自动化和显示配置。同时,可能在某些场景下我们需要混合使用JavaConfig和xml配置。
shirayner
2018/08/10
2610
Spring------自动化装配Bean(二) 一、在soundsystem 中新建JavaConfig2
上一篇是基于 @ComponentScan自动装配Bean的实现,这一篇将通过java手动装配bean来实现。
用户2417870
2019/09/18
2840
Spring_总结_03_装配Bean(一)之自动装配
(2)当必须要显示配置的时候,再使用类型安全并且比XML更强大的JavaConfig
shirayner
2018/08/10
3350
Spring------自动化装配Bean(三) 一、打开application.xml
上一篇是基于java手动装配bean的实现,这一篇将通过xml手动装配bean来实现。
用户2417870
2019/09/18
5110
Spring实战3:装配bean的进阶知识主要内容:
在装配bean—依赖注入的本质一文中,我们探讨了Spring的三种管理bean的方式:自动装配、基于JavaConfig、基于XML文件。这篇文字将探讨一些Spring中关于bean的管理的高级知识,这些技能你可能不会每天都用,但是非常重要。
阿杜
2018/08/06
1.2K0
Spring实战3:装配bean的进阶知识主要内容:
SpringBoot2 常用注解
在src/main/resources的META-INF/spring.factories
用户9615083
2022/12/25
3790
Spring_总结_03_装配Bean(二)之Java配置
上一节提到,装配Bean有三种方式,首先推荐自动装配。当自动装配行不通时,就需要采用显示配置的方式了。
shirayner
2018/08/10
1780
Spring实战4—面向切面编程主要内容
在南方没有暖气的冬天,太冷了,非常想念北方有暖气的冬天。为了取暖,很多朋友通过空调取暖,但是空调需要耗电,也就需要交不少电费。没家都会有一个电表,每隔一段时间都会有记录员来家里收取这段时间的电费。
阿杜
2018/08/06
9990
Spring实战4—面向切面编程主要内容
《Spring实战》读书笔记-第3章 高级装配
《Spring实战》是学习Spring框架的一本非常经典的书籍,之前阅读了这本书,只是在书本上写写画画,最近整理了一下《Spring实战》的读书笔记,通过博客的方式进行记录分享。俗话说,好记性不如烂笔头,把学习到的知识记录下来,方便温故知新,让更多的读者可以学习到有关Spring框架的知识。
Java架构师必看
2020/04/10
6810
再学习之Spring(依赖注入).
一、概述     Spring框架是以 简化Java EE应用程序的开发 为目标而创建的。Spring可以实现很多功能,但是这些功能的底层都依赖于它的两个核心特性,也就是依赖注入和面向切面编程。几乎Spring所做的任何事情都可以追溯到下述的一条或多条策略: 基于POJO的轻量级和最小侵入性编程; 通过依赖注入和面向接口实现松耦合; 基于切面和惯例进行声明式编程; 通过切面和模板减少样板式代码。      Spring的三个基本愿景: 使用DI来实现低耦合 使用AOP切面实现高内聚 使用模板消除样板式代码,
JMCui
2018/03/15
8440
再学习之Spring(依赖注入).
推荐阅读
相关推荐
Spring-2.装配
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文