Spring系统学习 -Spring IOC 的XML管理Bean之bean的获取、依赖注入值的方式

news2024/11/16 15:58:36

在Spring框架中,XML配置是最传统和最常见的方式之一,用于管理Bean的创建、依赖注入和生命周期等。这个在Spring中我们使用算是常用的,我们需要根据Spring的基于XML管理Bean了解相关Spring中常用的获取bean的方式、依赖注入值的几种方式等等。

基于XML方式管理bean的流程

  1. 创建XML配置文件:创建一个XML文件,用于定义Bean的配置信息和依赖关系。可以使用任何文本编辑器创建该文件,通常将其命名为"beans.xml"。
  2. 声明XML命名空间和模式位置:在XML文件的根元素中,声明Spring的命名空间和模式位置,以便正确解析和验证XML配置。
       <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">
    
  3. 定义Bean:使用元素来定义Bean,指定Bean的ID、类名和其他属性。示例如下:
    <bean id="userService" class="com.example.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>
    
    <bean id="userDao" class="com.example.UserDao"/>
    
  4. 加载XML配置文件:在Java代码中,使用ApplicationContext来加载XML配置文件。示例如下:
    public class Main {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        }
    }
    
  5. 获取Bean:通过ApplicationContext的getBean()方法,从容器中获取所需的Bean实例。示例如下:
    UserService userService = (UserService) context.getBean("userService");
    

搭建Spring模块结构

创建基本模块并引入相关配置

创建Spring模块
在这里插入图片描述
Spring 6 开始已经不在支持javaJDK 8了。

在pom.xml文件中引入相关依赖:

<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

<!--        引入Spring 依赖  5 的版本才支持 jdk8 , 6已经不在支持JDK8了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

<!--        引入阿里巴巴的数据库链接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.5</version>
        </dependency>

创建一个类HelloWorld

public class HelloWorld {
    public void sayHello(){
        System.out.println("Hello World!");
    }
}

创建一个Spring配置文件
在这里插入图片描述
存放到resources目录下
在这里插入图片描述
之后我们在创建的配置文件中配置Bean:

<!--
	配置HelloWorld所对应的bean,即将HelloWorld的对象交给Spring的IOC容器管理
	通过bean标签配置IOC容器所管理的bean
	属性:
		id:设置bean的唯一标识
		class:设置bean所对应类型的全类名
-->
<bean id="helloworld" class="com.miaow.spring.bean.HelloWorld"></bean>

接下来我们创建一个测试类

@Test
public void testHelloWorld(){
    ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");
    HelloWorld helloworld = (HelloWorld) ac.getBean("helloworld");
    helloworld.sayHello();
}

然后我们测试看一下是否输出正常。
在这里插入图片描述

大致流程
在这里插入图片描述
ps:Spring 底层默认通过反射技术调用组件类的无参构造器来创建组件对象,这一点需要注意。如果在需要无参构造器时,没有无参构造器,则会抛出下面的异常:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘helloworld’ defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.miaow.spring.bean.HelloWorld]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.miaow.spring.bean.HelloWorld.

获取Bean

根据ID获取

由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。
上述例子就是根据id获取一个组件对象。

public void testHelloWorld(){
    ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");
    //这个helloworld就是我们在xml配置文件设置的<bean id = "helloworld" >
    HelloWorld helloworld = (HelloWorld) ac.getBean("helloworld");
    helloworld.sayHello();
}
根据类型获取
@Test
public void testHelloWorld(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    HelloWorld bean = ac.getBean(HelloWorld.class);
    bean.sayHello();
}
根据id和类型获取
@Test
public void testHelloWorld(){
    ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");
    HelloWorld bean = ac.getBean("helloworld", HelloWorld.class);
    bean.sayHello();
}

当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个

例如:

<bean id="helloworldOne" class="com.miaow.spring.bean.HelloWorld"></bean>
<bean id="helloworldTwo" class="com.miaow.spring.bean.HelloWorld"></bean>

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.miaow.spring.bean.HelloWorld’ available: expected single matching bean but found 2: helloworldOne,helloworldTwo

  • 如果组件类实现了接口,根据接口类型可以获取 bean 吗?

    可以,前提是bean唯一

  • 如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?

    不行,因为bean不唯一

根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。

Spring依赖注入的方式

Spring的IoC(控制反转)容器通过依赖注入(DI)来管理应用程序中的组件之间的依赖关系。依赖注入是指将一个对象的依赖关系传递给另一个对象,而不是由被依赖对象自己创建或管理依赖对象。Spring框架提供了多种方式来实现依赖注入,包括构造器注入、Setter方法注入、字段注入、注解注入等。
至于字段注入和注解注入我们到Spring注解的时候再继续讲解,这里了解即可。

我们来创建一个学生实体类:

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;
    public Student() {
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Student{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", age=" + age +
            ", sex='" + sex + '\'' +
            '}';
    }
}
setter注入

我们通过Setter方式给上述的Student实体类注入相关值:

我们新建一个springdi.xml配置文件,然后在其中添加如下代码:

<bean id="studentOne" class="com.miaow.spring.bean.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关)-->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="23"></property>
    <property name="sex" value=""></property>
</bean>

接下来我们在测试类方法中测试

@Test
public void testDIBySet(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("springdi.xml");
    Student studentOne = ac.getBean("studentOne", Student.class);
    System.out.println(studentOne);
}
构造器注入

通过构造器注入将依赖项传递给bean
在实体类Student实体类中添加:

public Student(Integer id, String name, Integer age, String sex) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.sex = sex;
}

之后我们在springdi.xml文件中配置:

<bean id="studentTwo" class="com.miaow.spring.bean.Student">
    <constructor-arg value="1002"></constructor-arg>
    <constructor-arg value="李四"></constructor-arg>
    <constructor-arg value="33"></constructor-arg>
    <constructor-arg value=""></constructor-arg>
</bean>

注意:
constructor-arg标签还有两个属性可以进一步描述构造器参数:

  • index属性:指定参数所在位置的索引(从0开始)
  • name属性:指定参数名

测试类中进行测试:

@Test
public void testDIBySet(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("springdi.xml");
    Student studentOne = ac.getBean("studentTwo", Student.class);
    System.out.println(studentOne);
}

特殊值处理赋值

字面符

关于特殊值处理赋值,我们需要事先了解字面符。

什么是字面符?
int a = 10;


声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际上拿到的值是10。


而如果a是带引号的:‘a’,那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身。

例如

<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>
NULL
<!--表示name的值为空值-->
<property name="name">
	<null />
</property>

<!--写法同-->
<property name="name" value="null"></property>
<(小于) — XML实体

由于在XML中无法直接使用,故而我们需要用XML实体来代替

<property name="expression" value="a &lt; b"/>
CDARA节
<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
    <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
    <!-- 所以CDATA节中写什么符号都随意 -->
    <value><![CDATA[a < b]]></value>
</property>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1800248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构笔记1 绪论,线性表

学习视频&#xff1a; 第01周c--1.2基本概念和术语1_哔哩哔哩_bilibili 01《数据结构》绪论_哔哩哔哩_bilibili 数据&#xff1a; 1.数值型的数据&#xff1a;整数&#xff0c;实数 2.非数值型的数据&#xff1a;文字、图像.. 数据元素&#xff1a;&#xff08;元素&#xf…

四款优秀的电脑屏幕监控软件|监控电脑屏幕的必备软件

在选择监控电脑屏幕的软件时&#xff0c;我们需要考虑多个因素&#xff0c;包括软件的功能性、易用性、兼容性、安全性以及价格等。以下是几款在市场上广受好评的监控电脑屏幕的软件&#xff0c;它们各自具有独特的特点和优势。 1.安企神软件 安企神软件是一款专业的电脑屏幕监…

【电气学习六】HART仪表与HART信号

【电气学习六】HART仪表与HART信号 学习使人快乐 文章目录 【电气学习六】HART仪表与HART信号前言一、HART仪表是什么&#xff1f;二、HART协议1.什么是HART协议&#xff1f;2.HART协议的工作原理3.HART协议的特点4.HART协议的命令格式5.无源信号与有源信号的定义6.如何采集无源…

编写程序,提示用户输入以米/秒(m/s)为单位的速度v和以米/秒的平方(m/s)为单位的加速度 a,然后显示最短跑道长度。

(物理:求出跑道长度)假设一个飞机的加速度是a而起飞速度是v&#xff0c;那么可以使用下 面的公式计算出飞机起飞所需的最短跑道长度: 编写程序&#xff0c;提示用户输入以米/秒(m/s)为单位的速度v和以米/秒的平方(m/s)为单 位的加速度 a&#xff0c;然后显示最短跑道长度。下面…

C++基础与深度解析 | 模板 | 函数模板 | 类模板与成员函数模板 | concepts | 完美转发 | 模板的其他内容

文章目录 一、函数模板二、类模板与成员函数模板三、Concepts(C20)四、模板相关内容1.数值模板参数与模板模板参数2.别名模板与变长模板3.包展开与折叠表达式4.完美转发与lambda表达式模板5.消除歧义与变量模板 一、函数模板 在C中&#xff0c;函数模板是一种允许你编写可以处理…

GIGE 协议摘录 —— GVCP 协议(二)

系列文章目录 GIGE 学习笔记 GIGE 协议摘录 —— 设备发现&#xff08;一&#xff09; GIGE 协议摘录 —— GVCP 协议&#xff08;二&#xff09; GIGE 协议摘录 —— GVSP 协议&#xff08;三&#xff09; GIGE 协议摘录 —— 引导寄存器&#xff08;四&#xff09; GIGE 协议…

Allure在jenkins中无法显示的问题

jenkins中使用allure生成报告需要注意工作环境和路径的配置 前提条件&#xff1a; jenkins容器中已安装jdk和allure jenkins中配置全局工具环境&#xff1a; 项目中配置allure路径&#xff1a; 路径来源&#xff1a; Path需要选择相对路径的allure-report、allure-results

react快速开始(四)-之Vite 还是 (Create React App) CRA? 用Vite创建项目

文章目录 react快速开始(四)-之Vite 还是 (Create React App) CRA? 用Vite创建项目背景Vite 和 (Create React App) CRAVite&#xff1f;Vite 是否支持 TypeScript&#xff1f; 用Vite创建react项目参考 react快速开始(四)-之Vite 还是 (Create React App) CRA? 用Vite创建项…

劝大家:打个工而已,千万不要太老实,上周,我们单位一位兢兢业业,工作了20年的老员工,被公司辞退了...

学习资源已打包&#xff0c;需要的小伙伴可以戳这里 学习资料 在当今社会&#xff0c;职场竞争激烈&#xff0c;每个人都在努力工作&#xff0c;追求自己的目标。然而&#xff0c;随着工作经验的积累和观察的深入&#xff0c;我发现了一些工作中的现象&#xff0c;希望通过本文…

EE trade:通货膨胀时期投资什么最好

当通货膨胀来袭&#xff0c;货币购买力下降&#xff0c;闲置资金贬值速度加快。为了有效抵御通货膨胀&#xff0c;投资者需要选择能够保值甚至增值的投资工具。以下是几种在通货膨胀环境下较为理想的投资选择&#xff1a; 1. 投资股票 收益性和风险性&#xff1a;股票虽然风险…

寻找python库的安装路径

以pip库为例 要找到并修改 pip 库中的 __pip-runner__.py 文件&#xff0c;您可以按照以下步骤操作&#xff1a; 找到 pip 库的安装路径&#xff1a; 通常&#xff0c;Python 库会安装在您的虚拟环境或全局 Python 包目录中。您可以通过以下命令来找到 pip 库的路径&#xff1…

【代码随想录】【算法训练营】【第28天】 [93]复原IP地址 [78]子集 [90]子集II

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 28&#xff0c;工作的周二~ 题目详情 [93] 复原 IP 地址 题目描述 93 复原 IP 地址 解题思路 前提&#xff1a;分割问题 思路&#xff1a;回溯算法&#xff0c;确定每次递归回溯的分割位置…

【CTF-Web】XSS漏洞学习笔记(附ctfshow web316-333题目)

XSS 跨站脚本攻击 文章目录 XSS 跨站脚本攻击What is XSS&#xff1f;How to lead XSS&#xff1f;Where is the XSS&#xff1f;CookieHow to use XSS&#xff1f;反射型XSS存储型XSSDom-Based XSS Then Lets see the XSS in CTF各种过滤绕过学习web316Web317-319Web319-321We…

[经验] 蝉联一词的含义是什么 #知识分享#职场发展

蝉联一词的含义是什么 蝉联这个词起源于古代中国&#xff0c;最初是指天子连续两年以上的年号相同。后来&#xff0c;这个词被用于形容某个人或某个团体连续多次获得某种荣誉或奖项的情况。在现代生活中&#xff0c;我们常常听到某个体育运动员蝉联冠军、某个企业蝉联业绩排行榜…

编写程序提示用户输入一个数目(例如:100)、年利率(例如:5)以及月份数(例如:6),然后显示给定月份后账户上的钱数。

(财务应用程序:复利值)假设你每月向银行账户存 100美元&#xff0c;年利率为5%&#xff0c;那么每 月利率是 0.05/12-0.00417。 第一个月之后&#xff0c;账户上的值就变成:100*(10.00417)100.417 第二个月之后&#xff0c;账户上的值就变成(100100.417)*(10.00417)-201.252 第…

MySQL(三) - 基础操作

一、索引 由于我们在使用数据库的时候&#xff0c;大部分操作的都是查询操作&#xff0c;但是我们每一次进行查询都需要遍历一遍表中所有数据&#xff0c;这会花费O(n)的时间&#xff0c;因此数据引入了“索引” 也就是在底层使用了数据结构来进行优化查询的操作&#xff0c;但…

Ubuntu流体程序编译

文章目录 前言一、换源1.1 &#xff08;任意&#xff09;终端窗口输入1.2 在终端窗口依次输入下面命令 二、编译mpap程序----安装各类库2.1 安装 Eigen 库安装Lapack、VTK、SuperLU可以按照师弟文件给出的教程 2.2 安装Lapack2.3 安装VTK2.4 安装SuperLU2.5 安装其他包2.6 安装…

45-5 护网溯源 - 远控木马样本溯源

在分析恶意样本时&#xff0c;需要查看包括作者名字、ID、IP地址、域名等在内的相关信息。 把恶意样本上传到微步、360沙箱云分析&#xff1a;样本报告-微步在线云沙箱 (threatbook.com) 动态分析 运行截图 发现该木马是与一个装机软件绑定的&#xff0c;你运行正常软件的时候…

No module named _sqlite3解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

21 - 即时食物配送 II(高频 SQL 50 题基础版)

21 - 即时食物配送 II -- sum(if(order_datecustomer_pref_delivery_date,1,0))/count(*)sum(order_datecustomer_pref_delivery_date)/count(*) -- count(*),表示数据的行数&#xff0c;如果有分组&#xff0c;为分组后数据的行数select round(100*sum(if(order_datecustomer_…