先理解概念,再进行实际操作。概念比较偏术语化,第一次看可能看不懂,建议多看几遍,再尝试自己独立复述一遍,效果会好些
IOC (Inversion of Control),中文译为“控制反转”,是一种设计模式或者说设计原则,其核心理念是将原本在程序内部手动创建和管理对象(比如使用 `new` 关键字直接实例化对象)的责任转移给外部容器(如Spring框架中的IoC容器)。这种转移使得对象不再自己控制生命周期和相互依赖关系,而是由容器统一管理和维护。
在Spring框架中,IoC容器就像一个管家,负责创建对象(即所谓的“Spring Bean”,我们将由 IoC 容器管理的 Java 对象称为 Spring Bean)、管理它们的生命周期,并在Bean之间自动装配依赖关系。这意味着开发者不需要显式编码去创建或管理对象间的连接,从而极大地降低了代码之间的耦合度,提高了模块的可复用性和可测试性。
耦合度:
假设你正在做饭,你需要切菜和炒菜。如果每次炒菜前,你都必须先自己种菜、摘菜、洗菜,然后再切菜,那说明你炒菜的步骤跟种菜、摘菜、洗菜的步骤紧紧绑在一起,这就像是程序中的高耦合度——每个部分的工作都直接影响着另一个部分。
但如果有一个“厨房助手”帮你完成了种菜、摘菜、洗菜的工作,并且把干净的菜直接送到你面前让你切,那你只需要专注于炒菜就好,这就是降低了耦合度。在软件开发中,“厨房助手”就像是IoC容器,它帮你处理对象的创建和维护依赖关系等工作,使得各个组件(类或模块)能够独立运作,互不影响。
所以,耦合度简单来说就是指各个部分相互关联、影响的程度。在软件设计中,我们希望各个部分尽量独立、解耦,这样当修改其中一个部分时,不会连带影响到其他部分,从而使程序更易于维护和升级。
举例来说,你不用再在代码里写 `new UserService()` 去创建用户服务类的实例,而是通过配置文件或者注解告诉Spring容器应该怎样创建和管理UserService,Spring容器会根据配置自动创建并注入到需要的地方。这就是“控制反转”,控制权从程序员手中交给了容器,让容器成为组件生命周期和依赖关系的管理者。
反转的是什么?
如何实现控制反转?
依赖注入:指Spring创建对象的过程中,将对象依赖属性通过配置进行注入
举个栗子:
想象一下你在运营一家餐厅,每天需要制作汉堡。传统的做法是你自己买面包、肉饼、生菜等材料,然后亲手组合起来制作汉堡。这就好比在编程中,对象A需要对象B时,就自己创建一个新的对象B来使用。
现在引入“控制反转”(IoC)的概念,就好比你雇佣了一个经理来帮你经营餐厅。这位经理不仅负责采购所有食材,而且在你需要做汉堡时,他会直接将组装好的汉堡所需的所有材料(面包、肉饼、生菜)准备好并递给你。这里的“反转”是指原来由你自己做的事情(找材料、组装汉堡),现在改由外部的“经理”(IoC容器)来完成。
而“依赖注入”(DI)就是这位“经理”为你准备材料的具体操作方式:
setBread(Bread bread),经理就把面包塞进来了。MyHamburger(Bread bread, Patty patty, Lettuce lettuce),经理就是用这些材料来创建你的汉堡对象。总结一下:
在Spring框架中,IoC(Inversion of Control,控制反转)容器是用于实现依赖注入(DI)这一设计模式的核心组件。它负责管理应用程序中的对象(也就是所说的“bean”),包括对象的创建、初始化、装配依赖关系以及管理对象的生命周期。
BeanFactory:
ApplicationContext:
所以,在日常的Spring应用开发中,我们几乎总是直接使用ApplicationContext作为IoC容器,因为它提供了更加丰富的功能集和更高的便捷性。开发人员通常会通过ClassPathXmlApplicationContext、FileSystemXmlApplicationContext或其他方式来创建ApplicationContext实例,并通过它来获取和管理应用程序中的所有bean。
总的来说,IoC容器是用来帮我们创建和管理对象(bean)的,BeanFactory是基础版本,偏向于底层实现;而ApplicationContext是更高级、更全面的版本,是我们平时开发过程中接触和使用的主力工具。
ApplicationContext的主要实现类

| 类型名 | 简介 |
| ClassPathXmlApplicationContext | 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象 |
| FileSystemXmlApplicationContext | 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象 |
| ConfigurableApplicationContext | ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力。 |
| WebApplicationContext | 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中。 |
这一个大章节的视频案例可以结合尚硅谷Spring6视频看 --> 我是链接,点我
在这之前,建议在父工程中的pom文件里导入我们需要的依赖,这样其里面的子工程会自动添加,会方便许多~
父工程(Spring6)的pom.xml文件

导入相关依赖
- <!-- 依赖关系定义 -->
- <dependencies>
-
- <!--log4j2的依赖-->
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-core</artifactId>
- <version>2.19.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j2-impl</artifactId>
- <version>2.19.0</version>
- </dependency>
-
- <!-- 引入Spring Context依赖,它是Spring框架的基础模块,提供了环境配置、Bean生命周期管理、事件传播等功能 -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>6.0.2</version>
- </dependency>
-
- <!-- 引入JUnit5测试框架,用于编写和运行单元测试 -->
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-api</artifactId>
- <version>5.3.1</version>
- </dependency>
- </dependencies>

设置成功刷新后,Maven里应该是这样子的

在Spring6父工程中创建子模块



在子模块中创建配置文件--bean.xml
注意,是要创建在resources文件夹下,不然可能程序运行时找不到你的Spring配置文件,别问我是怎么知道的(T_T)

创建相关的User类,以便后续测试使用,注意有分包的好习惯
- package com.sakurapaid.spring.iocxml;
-
- public class User {
- private String name;
- private int age;
-
- public void test() {
- System.out.println("这是一个test测试输出~( ̄▽ ̄)/");
- }
- }

首先在bean.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="user" class="com.sakurapaid.spring.iocxml.User">
-
- </bean>
- </beans>

在Spring的XML配置文件中,
例如,在示例中,
再创建一个相关的测试类UserTest.Java
- package com.sakurapaid.spring.iocxml;
-
- public class UserTest {
- public static void main(String[] args) {
-
- }
- }

- // 方式一:根据Bean的id获取实例
- User user1 = (User) context.getBean("user");
- System.out.println(user1);
- // 方式二:根据Bean的类型获取实例
- User user2 = (User) context.getBean(User.class);
- System.out.println(user2);
- //方式三:根据Bean的id和类型获取实例
- User user3 = context.getBean("user", User.class);
- System.out.println(user3);
输出结果都是一样的
- /**
- * UserTest类用于演示通过XML配置文件进行Spring IOC(Inverse of Control)的简单示例。
- */
- package com.sakurapaid.spring.iocxml;
-
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class UserTest {
- /**
- * 主函数入口,演示了三种方式从Spring容器中获取Bean实例。
- */
- public static void main(String[] args) {
- // 创建Spring容器,使用ClassPathXmlApplicationContext加载名为"bean.xml"的配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
-
- // 方式一:根据Bean的id获取实例
- User user1 = (User) context.getBean("user");
- System.out.println(user1);
-
- // 方式二:根据Bean的类型获取实例
- User user2 = (User) context.getBean(User.class);
- System.out.println(user2);
-
- // 方式三:根据Bean的id和类型获取实例
- User user3 = context.getBean("user", User.class);
- System.out.println(user3);
- }
- }

在传统的编程方式中,我们通常需要在代码中通过 new 关键字创建对象实例,同时还需要手动管理对象之间的依赖关系。然而,在这段Spring的IoC示例中:
我们首先通过 ClassPathXmlApplicationContext 加载了名为 "bean.xml" 的Spring配置文件,这个配置文件中定义了Bean(这里是 User 类的实例)的创建方式和依赖关系。
然后,我们通过三种不同的方式从Spring容器中获取 User 类的实例:
在以上每一步中,都没有直接执行 new User() 来创建对象,而是由Spring IoC容器负责创建并管理这些对象。这就是所谓的“控制反转”:对象的创建控制权从应用代码转移到了Spring容器,从而实现了对象的生命周期管理、依赖关系注入等高级功能,减少了代码之间的耦合度,增强了系统的可维护性和可扩展性。
当在Spring的IoC容器中配置了两个相同类型的Bean时,例如:
- <bean id="user1" class="com.sakurapaid.spring.iocxml.User"></bean>
- <bean id="user2" class="com.sakurapaid.spring.iocxml.User"></bean>
这时,如果你试图仅根据类型(User.class)来获取Bean,Spring容器会因为无法确定具体应该返回哪个Bean实例而抛出异常。具体异常如下所示:
- org.springframework.beans.factory.NoUniqueBeanDefinitionException:
- No qualifying bean of type 'com.sakurapaid.spring.iocxml.User' available:
- expected single matching bean but found 2: user1, user2
这段错误信息表明,当Spring容器中存在多个同类型Bean定义时,若仅根据类型来查找,容器无法唯一确定应该返回哪一个Bean实例,因为按照类型查找期望得到的是唯一的匹配Bean。
在这种情况下,如果需要根据类型获取Bean,需要确保容器中对应类型的Bean只有一个,或者通过Bean的id来明确指定要获取的Bean。
UserDao接口

UserDaoImp01实现类

测试类

bean.xml配置文件
因为UserDao是一个接口,接口是不能有自己的对象,只能由实现它的类userDaoImp01来创建对象,所以下面
- <bean id="userDaoImp01"
- class="com.sakurapaid.spring.iocxml.interf.UserDaoImp01">
-
- </bean>
id="userDaoImp01":这部分指定了在Spring容器中的Bean的唯一标识符,通过这个ID,你可以从容器中获取或引用这个Bean实例。
class="com.sakurapaid.spring.iocxml.interf.UserDaoImp01":这部分定义了Bean的实现类,即当Spring容器创建这个Bean时,会使用这个类的信息来生成Bean的实例。尽管UserDao是个接口,但在实际应用中,我们需要通过其实现类UserDaoImp01来创建对象,因为接口不能实例化,只有具体的实现类才能生成对象实例。
此配置意味着Spring IoC容器将在启动时根据UserDaoImp01类的无参构造函数来创建一个Bean实例,并将其注册到容器中,之后在任何需要UserDao接口的地方,都可以通过Spring容器自动注入或通过getBean方法根据Bean的ID(这里是"userDaoImp01")来获取到这个实现了UserDao接口的具体实例。这就是Spring框架中的依赖注入(DI)机制。
测试输出结果

所以回答最上面的问题,如果就一个实现类实现了接口,根据接口类型可以获取 bean 吗?
是的,如果只有一个实现类实现了接口,并且这个实现类已经在Spring的IoC容器中配置为一个Bean,那么根据接口类型是可以成功获取到对应的Bean实例的。
前提条件:
class属性的值。例如在Spring配置文件中:
<bean id="userDao" class="com.sakurapaid.spring.iocxml.interf.UserDaoImp01"/>
然后在Java代码中,可以这样获取Bean:
- ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
- UserDao userDao = context.getBean(UserDao.class);
此时,由于只有UserDaoImp01实现了UserDao接口,并且已经被配置成Bean,因此根据UserDao.class类型可以从容器中顺利获取到对应的Bean实例。
不可以,如果一个接口有多个实现类,并且这些实现类都被配置成了Spring容器中的Bean,那么直接根据接口类型来获取Bean将会抛出NoUniqueBeanDefinitionException异常,因为Spring容器无法确定应该返回哪个Bean实例。
例如,有两个实现类UserDaoImp01和UserDaoImp02都实现了UserDao接口,并且都在Spring配置文件中配置为Bean:
- <bean id="userDaoImp01" class="com.sakurapaid.spring.iocxml.interf.UserDaoImp01"/>
- <bean id="userDaoImp02" class="com.sakurapaid.spring.iocxml.interf.UserDaoImp02"/>
总体结构

创建学生类Student
- package com.sakurapaid.spring.iocxml.di;
-
- public class Student {
- private String name;
- private int age;
-
- public Student() {
- }
-
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return age
- */
- public int getAge() {
- return age;
- }
-
- /**
- * 设置
- * @param age
- */
- public void setAge(int age) {
- this.age = age;
- }
-
- public String toString() {
- return "Student{name = " + name + ", age = " + age + "}";
- }
- }
bean-di.xml 配置文件
这里的
- "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="student" class="com.sakurapaid.spring.iocxml.di.Student">
-
- <property name="name" value="张三"> property>
-
- <property name="age" value="18"> property>
- bean>
- beans>

测试类
当Spring容器读取并解析bean-di.xml配置文件时,会创建一个Student实例,并通过调用对应的setter方法(setName和setAge),将值"张三"注入到name属性,将值18注入到age属性,从而完成依赖注入。
- package com.sakurapaid.spring.iocxml.di;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- /**
- * StudentTest类用于测试通过XML配置文件加载Bean的功能。
- */
- public class StudentTest {
-
- /**
- * 测试方法,通过ApplicationContext从XML配置文件中获取Bean实例。
- */
- @Test
- public void test(){
-
- // 创建ClassPathXmlApplicationContext实例,并加载名为"bean-di.xml"的配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
-
- // 通过上下文对象获取名为"student"的Bean实例,其类型为Student类
- Student student = context.getBean("student", Student.class);
-
- // 打印学生对象的信息
- System.out.println(student);
- }
- }
-

输出结果

在Student类中添加有参构造
- package com.sakurapaid.spring.iocxml.di;
-
- public class Student {
- private String name;
- private int age;
-
- public Student() {
- }
-
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
-
- public Student(String name) {
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return age
- */
- public int getAge() {
- return age;
- }
-
- /**
- * 设置
- * @param age
- */
- public void setAge(int age) {
- this.age = age;
- }
-
- public String toString() {
- return "Student{name = " + name + ", age = " + age + "}";
- }
- }
配置bean——spring-di.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">
-
- <!-- 定义一个名为student的bean,类型为com.sakurapaid.spring.iocxml.di.Student -->
- <!-- <bean id="student" class="com.sakurapaid.spring.iocxml.di.Student">
- <!– 设置student的name属性为"张三" –>
- <property name="name" value="张三"> </property>
- <!– 设置student的age属性为18 –>
- <property name="age" value="18"> </property>
- </bean>-->
-
-
- <!-- 定义一个名为studentcon的bean,类型为com.sakurapaid.spring.iocxml.di.Student -->
- <bean id="studentcon" class="com.sakurapaid.spring.iocxml.di.Student">
- <!-- 通过构造器参数name传入值"李四" -->
- <constructor-arg name="name" value="李四"> </constructor-arg>
- <!-- 通过构造器参数age传入值"19" -->
- <constructor-arg name="age" value="19"> </constructor-arg>
- </bean>
- </beans>

这里使用了
- public class Student {
- private String name;
- private int age;
-
- // 构造函数注入
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
- // 省略其他代码...
- }
constructor-arg标签还有两个属性可以进一步描述构造器参数:
index属性:指定参数所在位置的索引(从0开始)
name属性:指定参数名
测试结果
- package com.sakurapaid.spring.iocxml.di;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- /**
- * StudentTest类用于测试通过XML配置文件加载Bean的功能。
- */
- public class StudentTest {
-
- /**
- * 测试方法,通过ApplicationContext从XML配置文件中获取Bean实例。
- */
- /* @Test
- public void test(){
-
- // 创建ClassPathXmlApplicationContext实例,并加载名为"bean-di.xml"的配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
-
- // 通过上下文对象获取名为"student"的Bean实例,其类型为Student类
- Student student = context.getBean("student", Student.class);
-
- // 打印学生对象的信息
- System.out.println(student);
- }*/
-
- /**
- * 测试方法test01:通过Spring上下文加载并获取Bean实例。
- * 本方法不接受参数,也不返回值,主要演示如何从Spring配置文件中加载并获取Bean实例。
- */
- @Test
- public void test01(){
- // 创建ClassPathXmlApplicationContext实例,并加载名为"bean-di.xml"的配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
-
- // 通过上下文对象获取名为"student"的Bean实例,其类型为Student类
- Student student = context.getBean("studentcon", Student.class);
-
- // 打印学生对象的信息
- System.out.println(student);
- }
- }


当Spring容器加载并解析XML配置文件时,它会找到studentcon这个bean,并根据
最终,通过context.getBean("studentcon", Student.class)获取到了通过构造器注入生成的Student实例,并将其打印出来。
某些XML配置片段在Spring框架中的意义
当然,很高兴为您详细解释这些XML配置片段在Spring框架中的意义:
<property name="name" value="张三"/>
在Spring的XML配置中,标签是用来设置Bean属性值的。这里的value="张三"就是将字面量“张三”赋给名为"name"的属性。这意味着当你在Bean中引用该属性时,它的值就是字符串"张三",而不是一个变量或者表达式的结果。
- <property name="name">
- <null />
- </property>
这种方式是用来给Bean的属性设置null值的。与直接使用value="null"不同,后者会被当作字符串"null"而非实际的Java null值处理。 标签告诉Spring容器将此属性值设为空引用。
注意下面的这样写法
<property name="name" value="null"></property>
这样的写法,为name所赋的值是字符串null
<property name="expression" value="a < b"/>
在XML中,"<" 和 ">" 等特殊字符有特殊的含义,它们分别表示标签的开始和结束。如果你想在属性值中包含这样的字符,需要使用XML实体来转义。
例如,XML实体如 <代替小于号 < ,这样解析器就会知道这是一个小于符号,而不是标签的起始。
XML实体如 > 代替大于号 >
CDATA(Characters Data)是一种在XML文档中嵌入大段文本的方式,其中的内容不会被XML解析器解析为标记或实体。在这里,如果你的属性值可能包含大量的特殊字符或者需要包含XML语法结构,为了防止解析错误,可以将这部分内容放在之中。因此,意味着"a < b"被当作纯文本对待,里面的"<"字符不会被解析成标签开始。
总结来说,在Spring的XML配置中,这些不同的配置方式都是为了正确地传递和解析属性值,确保在初始化Bean时能获得预期的数据类型和内容。
准备工作

部门类Department
- package com.sakurapaid.spring.iocxml.diobj;
-
- public class Department {
- private String name;
-
- public void sout() {
- System.out.println("部门名: " + name);
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
- }
员工类Employee
- package com.sakurapaid.spring.iocxml.diobj;
-
- public class Employee {
- private Department department;
- private String name;
- private int age;
-
- public void work() {
- System.out.println("员工: " + name + ",年龄: " + age);
- department.sout();
- }
-
- public Department getDepartment() {
- return department;
- }
-
- public void setDepartment(Department department) {
- this.department = department;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
- }
配置bean文件——bean-diobj.xml
- "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="department" class="com.sakurapaid.spring.iocxml.diobj.Department">
-
- <property name="name" value="开发部"/>
- bean>
-
-
- <bean id="employee" class="com.sakurapaid.spring.iocxml.diobj.Employee">
-
- <property name="name" value="张三"/>
-
- <property name="age" value="20"/>
-
-
-
- <property name="department" ref="department"/>
- bean>
-
- beans>

测试输出
在测试类EmployeeTest中,我们通过Spring应用上下文加载XML配置文件,然后获取"employee"这个Bean的实例,并调用其work方法。由于依赖注入已经完成,此时调用employee.work()方法时,不仅会输出员工的基本信息,还会通过注入的department对象输出部门名称。
- package com.sakurapaid.spring.iocxml.diobj;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class EmployeeTest {
- @Test
- public void test() {
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
- Employee employee = context.getBean("employee", Employee.class);
- employee.work();
- }
- }


总结起来,这种引用外部bean的方式就是在配置文件中通过ref属性指定了依赖对象,Spring容器负责自动装配这些依赖关系,使得类之间的耦合度降低,提高了程序的可维护性和灵活性。
内部bean(Inner Bean)是在Spring配置文件中直接定义并初始化的一个Bean,它不是顶级Bean(Root Bean),而是作为另一个Bean的属性值出现。在给出的示例中,我们展示了如何通过内部bean的方式来注入Employee类的department属性。
在bean配置上和内部bean有所区别,但能达到一样的效果
在XML配置文件中,对于employee2这个Bean的定义,我们不再通过ref属性引用已经定义好的外部Bean,而是直接在其department属性内部定义一个新的Department Bean。
这里的新Department Bean没有显式定义ID,因为它是一个内部Bean,由Spring容器自动生成一个唯一的ID。同时,它拥有自己的属性设置,如name属性被设置为"开发部"。
- <?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方式-->
- <bean id="department" class="com.sakurapaid.spring.iocxml.diobj.Department">
- <property name="name" value="开发部"/>
- </bean>
- <bean id="employee1" class="com.sakurapaid.spring.iocxml.diobj.Employee">
- <property name="name" value="张三"/>
- <property name="age" value="20"/>
- <property name="department" ref="department"/>
- </bean>
-
- <!--内部bean方式-->
- <bean id="employee2" class="com.sakurapaid.spring.iocxml.diobj.Employee">
- <property name="name" value="张三"/>
- <property name="age" value="20"/>
- <property name="department">
- <bean class="com.sakurapaid.spring.iocxml.diobj.Department">
- <property name="name" value="开发部"/>
- </bean>
- </property>
- </bean>
-
- </beans>
测试输出
当Spring容器加载配置文件并初始化employee2这个Bean时,它会发现department属性需要注入一个Department类型的Bean。于是,它会在当前上下文中查找匹配的Bean定义,发现内部定义的Department Bean,然后创建并初始化这个内部Bean,并将其实例注入到employee2的department属性上。
在测试类EmployeeTest中,我们仅获取并操作了使用内部bean方式注入的Employee实例(employee2),同样能够达到与外部bean方式相同的效果,即输出员工基本信息以及所属部门名称。
内部bean方式的优势在于可以在同一个配置块内清晰地展示和组织Bean之间的依赖关系,简化配置文件结构。但在某些场景下,如果某个Bean会被多个其他Bean共享,使用外部bean并通过ref引用则更为合适。
- package com.sakurapaid.spring.iocxml.diobj;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class EmployeeTest {
- @Test
- public void test() {
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
- Employee employee = context.getBean("employee2", Employee.class);
- employee.work();
- }
- }


这种方式不常用,知道即可
- <?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方式-->
- <bean id="department" class="com.sakurapaid.spring.iocxml.diobj.Department">
- <property name="name" value="开发部"/>
- </bean>
- <bean id="employee1" class="com.sakurapaid.spring.iocxml.diobj.Employee">
- <property name="name" value="张三"/>
- <property name="age" value="20"/>
- <property name="department" ref="department"/>
- </bean>
-
- <!--内部bean方式-->
- <bean id="employee2" class="com.sakurapaid.spring.iocxml.diobj.Employee">
- <property name="name" value="张三"/>
- <property name="age" value="20"/>
- <property name="department">
- <bean class="com.sakurapaid.spring.iocxml.diobj.Department">
- <property name="name" value="开发部"/>
- </bean>
- </property>
- </bean>
-
- <!--级联属性赋值-->
- <bean id="department3" class="com.sakurapaid.spring.iocxml.diobj.Department">
- <property name="name" value="开发部"/>
- </bean>
-
- <bean id="employee3" class="com.sakurapaid.spring.iocxml.diobj.Employee">
- <property name="name" value="张三"/>
- <property name="age" value="20"/>
- <property name="department" ref="department3"/>
- <property name="department.name" value="测试部"/>
- </bean>
-
- </beans>
测试输出
- package com.sakurapaid.spring.iocxml.diobj;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class EmployeeTest {
- @Test
- public void test() {
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
- Employee employee = context.getBean("employee3", Employee.class);
- employee.work();
- }
- }


修改Employee员工类
主要是新增了数组成员和及其输出
- package com.sakurapaid.spring.iocxml.diobj;
-
- import java.util.Arrays;
-
- public class Employee {
- private Department department;
- private String name;
- private int age;
- private String[] hobby;
-
- public Employee() {
- }
-
- public Employee(Department department, String name, int age, String[] hobby) {
- this.department = department;
- this.name = name;
- this.age = age;
- this.hobby = hobby;
- }
-
- public void work() {
- System.out.println("员工: " + name + ",年龄: " + age);
- department.sout();
-
- // 遍历数组
- System.out.println(Arrays.toString(hobby));
-
- }
-
- /**
- * 获取
- * @return department
- */
- public Department getDepartment() {
- return department;
- }
-
- /**
- * 设置
- * @param department
- */
- public void setDepartment(Department department) {
- this.department = department;
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return age
- */
- public int getAge() {
- return age;
- }
-
- /**
- * 设置
- * @param age
- */
- public void setAge(int age) {
- this.age = age;
- }
-
- /**
- * 获取
- * @return hobby
- */
- public String[] getHobby() {
- return hobby;
- }
-
- /**
- * 设置
- * @param hobby
- */
- public void setHobby(String[] hobby) {
- this.hobby = hobby;
- }
-
- public String toString() {
- return "Employee{department = " + department + ", name = " + name + ", age = " + age + ", hobby = " + hobby + "}";
- }
- }


编辑spring配置文件
所以当Spring容器创建"employee"这个Bean时,它会自动将这些值("敲代码"、"阅读"和"打豆豆")注入到Employee对象的"hobby"数组属性中,最终得到的数组内容即为["敲代码", "阅读", "打豆豆"]。
- "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="department" class="com.sakurapaid.spring.iocxml.diobj.Department">
-
- <property name="name" value="开发部" />
- bean>
-
-
- <bean id="employee" class="com.sakurapaid.spring.iocxml.diobj.Employee">
-
- <property name="name" value="SakuraPaid"/>
-
- <property name="age" value="20"/>
-
- <property name="department" ref="department"/>
-
-
- <property name="hobby">
- <array>
- <value>敲代码value>
- <value>阅读value>
- <value>打豆豆value>
- array>
- property>
- bean>
-
- beans>


测试输出
- package com.sakurapaid.spring.iocxml.diobj;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class EmployeeTest {
- /**
- * 测试从Spring应用上下文中获取并使用Bean。
- * 该方法不接受参数,也不返回值。
- */
- @Test
- public void test() {
-
- // 创建一个ClassPathXmlApplicationContext,加载名为"bean-diarry.xml"的应用上下文配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-diarry.xml");
-
- // 从应用上下文中获取一个类型为Employee的Bean,Bean的名称为"employee"
- Employee employee = context.getBean("employee", Employee.class);
-
- // 调用获取的Employee Bean的work方法,模拟员工进行工作
- employee.work();
- }
- }


修改Department部门类
多了个List集合,一个部门有很多人,再定义个输出方法
- package com.sakurapaid.spring.iocxml.diobj;
-
- import java.util.List;
-
- public class Department {
-
- //一个部门有很多人
- private List<Employee> employees;
-
- //部门名称
- private String name;
-
- public void sout() {
- System.out.println("部门名: " + name);
- for (Employee emp : employees){
- System.out.println(emp.getName());
- }
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public List<Employee> getEmployees() {
- return employees;
- }
-
- public void setEmployees(List
employees ) { - this.employees = employees;
- }
- }

定义Spring配置文件
两个员工bean和一个部门bean
在XML配置文件中,首先定义了两个Employee类型的Bean(emp1和emp2),它们分别具有不同的属性值,包括名字、年龄和兴趣爱好列表(hobby)。这里的hobby属性是一个列表类型,使用标签进行配置,通过多个
然后,定义了一个Department类型的Bean(dept),它具有一个名字属性和一个employees集合属性。employees属性也是一个列表类型,用于存放Department下的多个Employee对象。这里使用标签,并通过子标签引用前面定义好的Employee Bean(emp1和emp2),从而将这两个Employee对象注入到Department的employees集合属性中。
- "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="emp1" class="com.sakurapaid.spring.iocxml.diobj.Employee">
-
- <property name="name" value="Tom" />
-
- <property name="age" value="20" />
-
- <property name="hobby">
- <list>
- <value>吃饭value>
- <value>睡觉value>
- <value>学习value>
- list>
- property>
- bean>
-
-
- <bean id="emp2" class="com.sakurapaid.spring.iocxml.diobj.Employee">
-
- <property name="name" value="Lucy" />
-
- <property name="age" value="21" />
-
- <property name="hobby">
- <list>
- <value>睡觉value>
- <value>学习value>
- <value>吃饭value>
- list>
- property>
- bean>
-
-
- <bean id="dept" class="com.sakurapaid.spring.iocxml.diobj.Department">
-
- <property name="name" value="财政部" />
-
- <property name="employees">
- <list>
-
- <ref bean="emp1" />
-
- <ref bean="emp2" />
- list>
- property>
- bean>
-
- beans>

测试输出
- package com.sakurapaid.spring.iocxml.diobj;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class EmployeeTest {
- /**
- * 测试从Spring应用上下文中获取并使用Bean的示例方法。
- * 该方法不接受任何参数。
- * 该方法也不返回任何值。
- */
- @Test
- public void test() {
-
- // 加载Spring应用上下文配置文件
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-dilist.xml");
-
- // 从应用上下文中获取指定名称的Bean
- Department dept = context.getBean("dept", Department.class);
-
- // 使用获取到的Bean执行某些操作
- dept.sout();
- }
-
- }

准备工作
创建一个学生类
- package com.sakurapaid.spring.iocxml.dimap;
-
- import java.util.Map;
-
- public class Student {
- private Map<String, Teacher> mapTeachers;
- private int stu_id;
- private String stu_name;
-
- public void sout(){
- System.out.println("学生id : " + stu_id + ", " +
- "学生姓名 : " + stu_name);
- System.out.print("教师集合 : ");
- System.out.println(mapTeachers);
- }
-
- public Map<String, Teacher> getMapTeachers() {
- return mapTeachers;
- }
-
- public void setMapTeachers(Map<String, Teacher> mapTeachers) {
- this.mapTeachers = mapTeachers;
- }
-
- public int getStu_id() {
- return stu_id;
- }
-
- public void setStu_id(int stu_id) {
- this.stu_id = stu_id;
- }
-
- public String getStu_name() {
- return stu_name;
- }
-
- public void setStu_name(String stu_name) {
- this.stu_name = stu_name;
- }
- }

创建一个老师类
- package com.sakurapaid.spring.iocxml.dimap;
-
- public class Teacher {
- private int teacherId;
- private String teacherName;
-
- public int getTeacherId() {
- return teacherId;
- }
-
- public void setTeacherId(int teacherId) {
- this.teacherId = teacherId;
- }
-
- public String getTeacherName() {
- return teacherName;
- }
-
- public void setTeacherName(String teacherName) {
- this.teacherName = teacherName;
- }
-
- //toString
- @Override
- public String toString() {
- return "Teacher [teacherId=" + teacherId + ", teacherName=" + teacherName + "]";
- }
- }
配置Spring文件
在Spring配置文件中,首先定义了两个Teacher类型的Bean(teacher1和teacher2),分别设置了他们的teacherId和teacherName属性。
然后,定义了一个Student类型的Bean(student),该Bean拥有stu_id和stu_name属性,同时还有一个名为mapTeachers的Map集合属性,用于存储不同科目的老师。
为mapTeachers属性赋值时,使用了标签,该标签用于表示Map集合。在标签内部,使用了多个
- <?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,教师编号为 1001,姓名为“语文老师” -->
- <bean id="teacher1" class="com.sakurapaid.spring.iocxml.dimap.Teacher">
- <property name="teacherId" value="1001" />
- <property name="teacherName" value="语文老师" />
- </bean>
-
- <!-- 定义一个教师 bean,教师编号为 1002,姓名为“数学老师” -->
- <bean id="teacher2" class="com.sakurapaid.spring.iocxml.dimap.Teacher">
- <property name="teacherId" value="1002" />
- <property name="teacherName" value="数学老师" />
- </bean>
-
- <!-- 定义一个学生 bean,学生编号为 1001,姓名为“张三”,并配置其对应的老师映射 -->
- <bean id="student" class="com.sakurapaid.spring.iocxml.dimap.Student">
- <property name="stu_id" value="1001" />
- <property name="stu_name" value="张三" />
- <!-- 老师映射,用以表示学生对应的不同科目老师 -->
- <property name="mapTeachers">
- <map>
- <!-- 映射“语文老师”到 teacher1 bean -->
- <entry key="语文老师" value-ref="teacher1" />
- <!-- 映射“数学老师”到 teacher2 bean -->
- <entry key="数学老师" value-ref="teacher2" />
- </map>
- </property>
- </bean>
-
- </beans>

测试输出
- package com.sakurapaid.spring.iocxml.dimap;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class MapTest {
- /**
- * 测试从配置文件中获取Bean并调用其方法。
- */
- @Test
- public void test(){
- // 加载配置文件,创建ApplicationContext上下文
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-dimap.xml");
-
- // 通过上下文获取名为"student"的Bean实例
- Student student = context.getBean("student", Student.class);
-
- // 调用Student实例的sout方法
- student.sout();
- }
- }

修改学生类
新增一个List集合,管理课程
- package com.sakurapaid.spring.iocxml.dimap;
-
- import java.util.List;
- import java.util.Map;
-
- public class Student {
- private Map<String, Teacher> mapTeachers;
-
- private List<Lesson> listLessons;
- private int stu_id;
- private String stu_name;
-
- /**
- * 此方法用于输出学生的详细信息,包括学生ID、学生姓名,以及该学生所属的教师集合和课程集合。
- * 该方法不接受参数,也不返回任何值。
- */
- public void sout(){
- // 输出学生的基本信息
- System.out.println("学生id : " + stu_id + ", " +
- "学生姓名 : " + stu_name);
-
- // 输出教师集合
- System.out.print("教师集合 : "); //只输出老师名字
- for(Map.Entry<String, Teacher> entry : mapTeachers.entrySet()){
- System.out.print(entry.getValue().getTeacherName() + " ");
- }
- System.out.println();
- // 输出课程集合
- System.out.print("课程集合 : ");
- for(Lesson lesson : listLessons){
- System.out.print(lesson.getLessonName() + " ");
- }
- }
-
- public Map<String, Teacher> getMapTeachers() {
- return mapTeachers;
- }
-
- public void setMapTeachers(Map<String, Teacher> mapTeachers) {
- this.mapTeachers = mapTeachers;
- }
-
- public int getStu_id() {
- return stu_id;
- }
-
- public void setStu_id(int stu_id) {
- this.stu_id = stu_id;
- }
-
- public String getStu_name() {
- return stu_name;
- }
-
- public void setStu_name(String stu_name) {
- this.stu_name = stu_name;
- }
-
- public List<Lesson> getListLessons() {
- return listLessons;
- }
-
- public void setListLessons(List
listLessons ) { - this.listLessons = listLessons;
- }
- }


其对应的Lesson课程类
- package com.sakurapaid.spring.iocxml.dimap;
-
- public class Lesson {
- private String lessonName;
-
- public String getLessonName() {
- return lessonName;
- }
-
- public void setLessonName(String lessonName) {
- this.lessonName = lessonName;
- }
- }
配置Spring文件
使用util:list、util:map标签必须引入相应的命名空间
代码样式放在上的,需要用时直接复制粘贴即可
- "1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:util="http://www.springframework.org/schema/util"
- xsi:schemaLocation="http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
完整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"
- xmlns:util="http://www.springframework.org/schema/util"
- xsi:schemaLocation="http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
-
- <!-- 定义一个学生 bean,学生编号为 1001,姓名为“张三” -->
- <bean id="student" class="com.sakurapaid.spring.iocxml.dimap.Student">
- <property name="stu_id" value="1001" />
- <property name="stu_name" value="张三" />
- <property name="listLessons" ref="listLessons" />
- <property name="mapTeachers" ref="mapTeachers" />
- </bean>
-
- <!-- 定义一个教师列表,包含两个教师 bean -->
- <util:list id="listLessons" >
- <ref bean="lesson1" />
- <ref bean="lesson2" />
- </util:list>
-
- <!-- 定义一个教师映射,key为教师编号,value为教师 bean 的引用 -->
- <util:map id="mapTeachers" >
- <entry key="1001" value-ref="teacher1" />
- <entry key="1002" value-ref="teacher2" />
- </util:map>
-
- <!-- 定义一个教师 bean,教师编号为 1001,姓名为“语文老师” -->
- <bean id="teacher1" class="com.sakurapaid.spring.iocxml.dimap.Teacher">
- <property name="teacherId" value="1001" />
- <property name="teacherName" value="语文老师" />
- </bean>
-
- <!-- 定义一个教师 bean,教师编号为 1002,姓名为“数学老师” -->
- <bean id="teacher2" class="com.sakurapaid.spring.iocxml.dimap.Teacher">
- <property name="teacherId" value="1002" />
- <property name="teacherName" value="数学老师" />
- </bean>
-
- <!-- 定义一个课程 bean,课程名称为“语文课”-->
- <bean id="lesson1" class="com.sakurapaid.spring.iocxml.dimap.Lesson">
- <property name="lessonName" value="语文课" />
- </bean>
-
- <!-- 定义一个课程 bean,课程名称为“数学课”-->
- <bean id="lesson2" class="com.sakurapaid.spring.iocxml.dimap.Lesson">
- <property name="lessonName" value="数学课" />
- </bean>
-
- </beans>

测试输出
- package com.sakurapaid.spring.iocxml.dimap;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class MapAndListTest {
- /**
- * 测试从XML配置文件中获取Bean实例并进行操作的方法。
- * 该方法不接受参数,也不返回值,但通过ApplicationContext从XML配置文件中获取Student类型的Bean实例,并对其进行操作。
- */
- @Test
- public void test(){
- // 加载名为"bean-diMapAndList.xml"的XML配置文件,创建ApplicationContext上下文
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-diMapAndList.xml");
-
- // 从上下文中获取名为"student"的Bean实例,其类型为Student
- Student student = context.getBean("student", Student.class);
-
- // 调用Student实例的sout方法,输出相关信息
- student.sout();
- }
- }

引入p命名空间
- "1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:util="http://www.springframework.org/schema/util"
- xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">

引入p命名空间后,可以通过以下方式为bean的各个属性赋值
- <!-- p命名空间方式 -->
- <bean id="student1" class="com.sakurapaid.spring.iocxml.dimap.Student"
- p:stu_id="1411" p:stu_name="李四" p:listLessons-ref="lesson1" p:mapTeachers-ref="mapTeachers">
- </bean>
完整配置Spring文件
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:util="http://www.springframework.org/schema/util"
- xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/util
- http://www.springframework.org/schema/util/spring-util.xsd
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd">
-
- <!-- p命名空间方式 -->
- <bean id="student1" class="com.sakurapaid.spring.iocxml.dimap.Student"
- p:stu_id="1411" p:stu_name="李四" p:listLessons-ref="lesson1" p:mapTeachers-ref="mapTeachers">
- </bean>
-
- <!-- 定义一个学生 bean,学生编号为 1001,姓名为“张三” -->
- <bean id="student" class="com.sakurapaid.spring.iocxml.dimap.Student">
- <property name="stu_id" value="1001" />
- <property name="stu_name" value="张三" />
- <property name="listLessons" ref="listLessons" />
- <property name="mapTeachers" ref="mapTeachers" />
- </bean>
-
- <!-- 定义一个教师列表,包含两个教师 bean -->
- <util:list id="listLessons" >
- <ref bean="lesson1" />
- <ref bean="lesson2" />
- </util:list>
-
- <!-- 定义一个教师映射,key为教师编号,value为教师 bean 的引用 -->
- <util:map id="mapTeachers" >
- <entry key="1001" value-ref="teacher1" />
- <entry key="1002" value-ref="teacher2" />
- </util:map>
-
- <!-- 定义一个教师 bean,教师编号为 1001,姓名为“语文老师” -->
- <bean id="teacher1" class="com.sakurapaid.spring.iocxml.dimap.Teacher">
- <property name="teacherId" value="1001" />
- <property name="teacherName" value="语文老师" />
- </bean>
-
- <!-- 定义一个教师 bean,教师编号为 1002,姓名为“数学老师” -->
- <bean id="teacher2" class="com.sakurapaid.spring.iocxml.dimap.Teacher">
- <property name="teacherId" value="1002" />
- <property name="teacherName" value="数学老师" />
- </bean>
-
- <!-- 定义一个课程 bean,课程名称为“语文课”-->
- <bean id="lesson1" class="com.sakurapaid.spring.iocxml.dimap.Lesson">
- <property name="lessonName" value="语文课" />
- </bean>
-
- <!-- 定义一个课程 bean,课程名称为“数学课”-->
- <bean id="lesson2" class="com.sakurapaid.spring.iocxml.dimap.Lesson">
- <property name="lessonName" value="数学课" />
- </bean>
-
- </beans>
输出测试
- package com.sakurapaid.spring.iocxml.dimap;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class MapAndListTest {
- /**
- * 测试从XML配置文件中获取Bean实例并进行操作的方法。
- * 该方法不接受参数,也不返回值,但通过ApplicationContext从XML配置文件中获取Student类型的Bean实例,并对其进行操作。
- */
- @Test
- public void test(){
- // 加载名为"bean-diMapAndList.xml"的XML配置文件,创建ApplicationContext上下文
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-diMapAndList.xml");
-
- // 从上下文中获取名为"student"的Bean实例,其类型为Student
- Student student = context.getBean("student1", Student.class);
-
- // 调用Student实例的sout方法,输出相关信息
- student.sout();
- }
- }

在Spring框架中,引入外部属性文件是一种管理应用程序配置的有效方法。当我们在Spring的XML配置文件中直接编写大量的固定配置信息(如数据库用户名、密码、URL,或是服务器IP地址、端口号等),这些信息如果频繁变动,将会使得配置文件变得难以维护,而且每当配置信息发生变化时,开发人员就需要打开源代码去修改XML配置文件,然后再重新打包部署项目,这是一个繁琐的过程。
为了解决这个问题,Spring支持将这些容易变化的配置项提取出来,存放在单独的properties文件中,如database.properties或application.properties。这些文件通常包含键值对的形式,例如:
database.properties文件
- db.username=admin
- db.password=secretpassword
- db.url=jdbc:mysql://localhost:3306/mydatabase
接下来,在Spring的XML配置文件中,我们可以使用PropertyPlaceholderConfigurer(在较旧版本中)或(在Spring 3.1及以上版本推荐使用)来引入和解析这些外部属性文件:
- <!-- Spring 3.1+ 使用context命名空间简化引入 -->
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="...">
-
- <!-- 引入外部属性文件 -->
- <context:property-placeholder location="classpath:database.properties"/>
-
- <!-- 使用外部属性文件中的值注入Bean -->
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="username" value="${db.username}"/>
- <property name="password" value="${db.password}"/>
- <property name="url" value="${db.url}"/>
- </bean>
- </beans>
这样一来,当数据库的连接信息需要变更时,我们只需要修改database.properties文件,而不需要碰触到Spring的XML配置文件或Java代码。这样既实现了配置的模块化,又增强了配置的可维护性,同时降低了因配置变更导致的应用程序整体重新部署的频率。此外,这种模式还可以方便地根据不同的环境(如开发、测试、生产)切换不同的配置文件,实现灵活部署。
比如你下面的例子,你就会懂了
加入依赖
- <!-- MySQL驱动 -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>8.0.25</version>
- </dependency>
- <!-- 数据源 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.2.15</version>
- </dependency>
创建外部属性文件 —— jdbc.properties
- jdbc.user=root
- jdbc.password=atguigu
- jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
- jdbc.driver=com.mysql.cj.jdbc.Driver

引入属性文件
引入context 名称空间,下面这是模版,可以直接复制
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context.xsd">
-
- </beans>
其实你也可以发现,就是在用的最多的beans,改个单词而已,以后可以尝试自己手动修改试试
在spring配置文件中,引入外部属性文件
- <context:property-placeholder location="classpath:jdbc.properties"/>

进行bean配置
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context.xsd">
-
- <!-- 引入外部属性文件 -->
- <context:property-placeholder location="classpath:jdbc.properties"/>
-
- <!--完成数据库的连接池的配置-->
- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
- <property name="url" value="${jdbc.url}"/>
- <property name="driverClassName" value="${jdbc.driver}"/>
- <property name="username" value="${jdbc.user}"/>
- <property name="password" value="${jdbc.password}"/>
- </bean>
-
- </beans>
测试输出
- package com.sakurapaid.spring.iocxml.jbdc;
-
- import com.alibaba.druid.pool.DruidDataSource;
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class JDBCtest {
- @Test
- public void test(){
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-jdbc.xml");
- DruidDataSource dataSource = (DruidDataSource) context.getBean("dataSource");
- System.out.println(dataSource.getUrl());;
- }
- }

像这样,以后要改的话,直接从.properties文件中修改即可,省去了xml操作的麻烦步骤
在Spring框架中,Bean(Java对象)的作用域指的是在应用程序的整个生命周期中,对于某个特定的Bean对象,Spring容器是如何管理和创建其实例的。Bean的作用域决定了容器在何时以及如何创建Bean实例,以及这些实例之间的关系。
作用域的视频例子可以看B站尚硅谷的视频 --> 尚硅谷Spring6
| 取值 | 含义 | 创建对象的时机 |
| singleton(默认) | 在IOC容器中,这个bean的对象始终为单实例 | IOC容器初始化时 |
| prototype | 这个bean在IOC容器中有多个实例 | 获取bean时 |
①singleton作用域:
举个例子:
②prototype作用域:
getBean()方法被调用时都会产生一个新的对象实例。ApplicationContext.getBean()方法请求一个prototype类型的Bean时,Spring容器才会创建新的实例。举个例子:
关于Bean的生命周期:
除了Bean的作用域之外,Bean还有一个完整的生命周期,它包括以下几个阶段:
BeanPostProcessor接口提供了两个方法postProcessBeforeInitialization()和postProcessAfterInitialization(),在这一步骤中,Spring会调用postProcessBeforeInitialization()方法对Bean进行自定义的预处理。InitializingBean接口,若实现了则调用afterPropertiesSet()方法;或者在配置文件中通过init-method属性指定了初始化方法,此时Spring容器会调用该方法对Bean进行初始化。postProcessAfterInitialization()方法进一步处理Bean。这一阶段可用于在Bean正式投入使用前进行一些补充性的定制化工作。getBean()方法,可以在应用程序中任意位置获取并使用这个Bean实例。DisposableBean接口,则调用destroy()方法;或者在配置文件中通过destroy-method属性指定了销毁方法,Spring容器会调用该方法释放资源,如关闭数据库连接、清除缓存等,这就好比客人用餐结束后清理餐具、打扫卫生。总的来说,在Spring框架中,Bean的作用域是指Bean实例的创建策略,而生命周期则是指Bean实例从创建到销毁的过程。通过理解并合理配置Bean的作用域和生命周期,可以更好地管理和控制Bean实例的行为,提高应用效率和资源利用率。
举个例子
User类
- package com.sakurapaid.spring.iocxml.life;
-
- public class User {
- private String name;
-
- //初始化方法
- public void init() {
- System.out.println("生命周期:3、初始化~");
- }
-
- //销毁方法
- public void destroy() {
- System.out.println("生命周期:5、销毁~");
- }
-
- public User() {
- System.out.println("生命周期:1、创建对象~");
- }
-
- public User(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- System.out.println("生命周期:2、依赖注入~");
- this.name = name;
- }
-
- public String toString() {
- return "User{name = " + name + "}";
- }
- }
配置Spring文件
- "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="user" class="com.sakurapaid.spring.iocxml.life.User"
- scope="singleton" init-method="init" destroy-method="destroy">
-
- <property name="name" value="sakura" />
-
- bean>
-
-
-
- beans>
测试输出
- package com.sakurapaid.spring.iocxml.life;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class UserTest {
- @Test
- public void test(){
- //想要实现bean生命周期的销毁,需要使用ClassPathXmlApplicationContext
- //而不是用ApplicationContext,它里面没有destroy方法
- ClassPathXmlApplicationContext context = new
- ClassPathXmlApplicationContext("bean-life.xml");
-
- User bean = context.getBean(User.class);
- System.out.println("生命周期:4、通过IOC容器获取bean并使用~");
- bean.destroy();
- }
- }

以上是没有设置后置处理器的bean基本生命周期
下面的例子就是加上后置处理器的样子
修改后的User类
- package com.sakurapaid.spring.iocxml.life;
-
- public class User {
- private String name;
-
- //初始化方法
- public void init() {
- System.out.println("生命周期:4、初始化~");
- }
-
- //销毁方法
- public void destroy() {
- System.out.println("生命周期:7、销毁~");
- }
-
- public User() {
- System.out.println("生命周期:1、创建对象~");
- }
-
- public User(String name) {
- this.name = name;
- }
-
- /**
- * 获取
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * 设置
- * @param name
- */
- public void setName(String name) {
- System.out.println("生命周期:2、依赖注入~");
- this.name = name;
- }
-
- public String toString() {
- return "User{name = " + name + "}";
- }
- }
创建bean的后置处理器
- package com.sakurapaid.spring.iocxml.life;
-
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.config.BeanPostProcessor;
-
- /**
- * MyBeanProcessor 类实现了 BeanPostProcessor 接口,
- * 用于在 Spring 容器初始化 bean 之前和之后对 bean 进行处理。
- */
- public class MyBeanProcessor implements BeanPostProcessor {
-
- /**
- * 在 Spring 初始化 bean 之前调用此方法。
- *
- * @param bean 将要被初始化的 bean 对象。
- * @param beanName bean 的名称。
- * @return 返回经过处理的 bean 对象。
- * @throws BeansException 如果处理中发生错误。
- */
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- System.out.println("生命周期:3、bean的后置处理器(初始化之前)");
- System.out.println("☆☆☆" + beanName + " = " + bean);
- return bean;
- }
-
- /**
- * 在 Spring 初始化 bean 之后调用此方法。
- *
- * @param bean 已经被初始化的 bean 对象。
- * @param beanName bean 的名称。
- * @return 返回经过处理的 bean 对象。
- * @throws BeansException 如果处理中发生错误。
- */
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- System.out.println("生命周期:5、bean的后置处理器(初始化之后)");
- System.out.println("★★★" + beanName + " = " + bean);
- return bean;
- }
- }
-
修改后的Spring配置文件
- <bean id="myBeanProcessor" class="com.atguigu.spring6.process.MyBeanProcessor"/>
完整xml代码
- "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="user" class="com.sakurapaid.spring.iocxml.life.User"
- scope="singleton" init-method="init" destroy-method="destroy">
-
-
- <property name="name" value="sakura" />
-
- bean>
-
-
- <bean id="myBeanProcessor" class="com.sakurapaid.spring.iocxml.life.MyBeanProcessor"/>
-
-
-
- beans>
测试输出
- package com.sakurapaid.spring.iocxml.life;
-
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class UserTest {
- @Test
- public void test(){
- //想要实现bean生命周期的销毁,需要使用ClassPathXmlApplicationContext
- //而不是用ApplicationContext,它里面没有destroy方法
- ClassPathXmlApplicationContext context = new
- ClassPathXmlApplicationContext("bean-life.xml");
-
- User bean = context.getBean(User.class);
- System.out.println("生命周期:6、通过IOC容器获取bean并使用~");
- bean.destroy();
- }
- }

普通Bean
想象一下,在一个家具工厂里,每种家具都有对应的生产线工人,他们负责制造特定的家具产品,比如椅子。在Spring IoC容器中,一个普通的Java类(如ComfyChair)被声明为bean后,Spring容器就像那个家具工厂,它会通过反射等机制,按照你在配置文件或者注解中的定义,实例化出一个ComfyChair对象放入容器中。当你请求容器获取一个名为"comfyChair"的bean时,容器直接返回一个ComfyChair类型的实例。
- public class ComfyChair {}
-
- // 配置文件或注解方式声明普通bean
- <bean id="comfyChair" class="com.example.ComfyChair" />
-
- // 或者使用注解
- @Service("comfyChair")
- public class ComfyChair {}
FactoryBean
现在,假设工厂引入了一台高级智能机器,这台机器本身就是一个生产家具的“工厂”,我们称它为“智能椅制造机”(对应Spring中的FactoryBean)。这台机器实现了特殊接口FactoryBean,它的作用不是生产“智能椅制造机”自身,而是生产椅子。
在Spring中,如果你有一个类SmartChairFactory实现了FactoryBean接口,并且重写了getObject()方法,那么当Spring容器读取到这个bean定义时,它不会直接生成一个SmartChairFactory实例,而是调用SmartChairFactory的getObject()方法来获取实际的产品——一个ComfyChair实例或者其他类型的实例。
- public class SmartChairFactory implements FactoryBean<ComfyChair> {
- @Override
- public ComfyChair getObject() throws Exception {
- // 这里可能包含复杂的创建逻辑,如依赖注入、组装等
- return new ComfyChair();
- }
-
- @Override
- public Class<?> getObjectType() {
- return ComfyChair.class;
- }
-
- // 其他必要方法...
- }
-
- // 声明FactoryBean
- <bean id="chairFactory" class="com.example.SmartChairFactory" />
-
- // 当你请求id为"chairFactory"的bean时
- // Spring容器不会返回SmartChairFactory对象,而是返回getObject()方法创建的ComfyChair对象
总结:
getObject()方法创建的bean实例,而非FactoryBean本身的实例。FactoryBean常用于那些需要复杂初始化逻辑、代理对象生成或其他特殊场景的情况。将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
再来个代码例子举例一下,你应该就会懂了( ̄▽ ̄)/
创建类UserFactoryBean
- package com.sakurapaid.spring.iocxml.life;
-
- import org.springframework.beans.factory.FactoryBean;
-
- public class UserFactoryBean implements FactoryBean<User> {
- @Override
- public User getObject() throws Exception {
- return new User();
- }
-
- @Override
- public Class> getObjectType() {
- return User.class;
- }
- }
配置spring的相关bean
- "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="user" class="com.sakurapaid.spring.iocxml.life.UserFactoryBean" />
-
- beans>
测试输出
- F:\Develop\JDK17\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:F:\Develop\IDEA\IntelliJ IDEA 2023.3.3\lib\idea_rt.jar=11512:F:\Develop\IDEA\IntelliJ IDEA 2023.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Users\ASUS\.m2\repository\org\junit\platform\junit-platform-launcher\1.3.1\junit-platform-launcher-1.3.1.jar;C:\Users\ASUS\.m2\repository\org\apiguardian\apiguardian-api\1.0.0\apiguardian-api-1.0.0.jar;C:\Users\ASUS\.m2\repository\org\junit\platform\junit-platform-engine\1.3.1\junit-platform-engine-1.3.1.jar;C:\Users\ASUS\.m2\repository\org\junit\platform\junit-platform-commons\1.3.1\junit-platform-commons-1.3.1.jar;C:\Users\ASUS\.m2\repository\org\opentest4j\opentest4j\1.1.1\opentest4j-1.1.1.jar;C:\Users\ASUS\.m2\repository\org\junit\jupiter\junit-jupiter-engine\5.3.1\junit-jupiter-engine-5.3.1.jar;C:\Users\ASUS\.m2\repository\org\junit\jupiter\junit-jupiter-api\5.3.1\junit-jupiter-api-5.3.1.jar;F:\Develop\IDEA\IntelliJ IDEA 2023.3.3\lib\idea_rt.jar;F:\Develop\IDEA\IntelliJ IDEA 2023.3.3\plugins\junit\lib\junit5-rt.jar;F:\Develop\IDEA\IntelliJ IDEA 2023.3.3\plugins\junit\lib\junit-rt.jar;F:\Program\Java\Spring6\Spring6-ioc-xml\target\classes;F:\Develop\apache\LocalMavenWarehouse\org\apache\logging\log4j\log4j-core\2.19.0\log4j-core-2.19.0.jar;F:\Develop\apache\LocalMavenWarehouse\org\apache\logging\log4j\log4j-api\2.19.0\log4j-api-2.19.0.jar;F:\Develop\apache\LocalMavenWarehouse\org\apache\logging\log4j\log4j-slf4j2-impl\2.19.0\log4j-slf4j2-impl-2.19.0.jar;F:\Develop\apache\LocalMavenWarehouse\org\slf4j\slf4j-api\2.0.0\slf4j-api-2.0.0.jar;F:\Develop\apache\LocalMavenWarehouse\org\springframework\spring-context\6.0.2\spring-context-6.0.2.jar;F:\Develop\apache\LocalMavenWarehouse\org\springframework\spring-aop\6.0.2\spring-aop-6.0.2.jar;F:\Develop\apache\LocalMavenWarehouse\org\springframework\spring-beans\6.0.2\spring-beans-6.0.2.jar;F:\Develop\apache\LocalMavenWarehouse\org\springframework\spring-core\6.0.2\spring-core-6.0.2.jar;F:\Develop\apache\LocalMavenWarehouse\org\springframework\spring-jcl\6.0.2\spring-jcl-6.0.2.jar;F:\Develop\apache\LocalMavenWarehouse\org\springframework\spring-expression\6.0.2\spring-expression-6.0.2.jar;F:\Develop\apache\LocalMavenWarehouse\org\junit\jupiter\junit-jupiter-api\5.3.1\junit-jupiter-api-5.3.1.jar;F:\Develop\apache\LocalMavenWarehouse\org\apiguardian\apiguardian-api\1.0.0\apiguardian-api-1.0.0.jar;F:\Develop\apache\LocalMavenWarehouse\org\opentest4j\opentest4j\1.1.1\opentest4j-1.1.1.jar;F:\Develop\apache\LocalMavenWarehouse\org\junit\platform\junit-platform-commons\1.3.1\junit-platform-commons-1.3.1.jar;F:\Develop\apache\LocalMavenWarehouse\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar;F:\Develop\apache\LocalMavenWarehouse\com\google\protobuf\protobuf-java\3.11.4\protobuf-java-3.11.4.jar;F:\Develop\apache\LocalMavenWarehouse\com\alibaba\druid\1.2.15\druid-1.2.15.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 com.sakurapaid.spring.iocxml.life.UserTest
- 2024-03-17 16:47:46 194 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@71454b9d
- 2024-03-17 16:47:46 302 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [bean-factorbean.xml]
- 2024-03-17 16:47:46 328 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'user'
- 生命周期:1、创建对象~
- User{name = null}

自动装配:
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
Spring自动装配,你可以理解为Spring框架的一种智能助手,它能在背后悄悄帮你处理Bean之间的关联关系。当你定义了一些Bean,并告诉Spring使用自动装配时,Spring会在创建这些Bean时,自动找出并填充它们所需要的依赖对象。
打个比方,假设你在装修房子,有电工、木工和油漆工三个工种。如果没有自动装配,你需要亲自安排电工去做电线安装,木工去做家具组装,油漆工去做刷漆工作。而有了自动装配功能,你只需要告诉Spring哪个房间需要装修,Spring会根据每个工人的技能(电工擅长电,木工擅长木工活,油漆工擅长刷漆)自动分配任务,不需要你一一指定谁去做什么。
在Spring中,不同的自动装配策略相当于不同的分工规则,比如按名字找合适的工人(byName)、按工种找合适的工人(byType)等。这样,你就可以更加专注于整体的设计和规划,而无需过于关注每个细小环节的具体实施。
主要有以下几种自动装配策略:
通过启用自动装配功能,Spring可以帮助开发者减少大量手动配置依赖注入的工作,提高开发效率,同时保持代码结构清晰。不过,过度依赖自动装配可能会导致问题不易排查,因此在实际项目中应合理权衡是否使用自动装配以及选择哪种装配策略。
总之,自动装配就是Spring帮你自动完成对象间的依赖关系建立,让你编写代码时更轻松,不过要注意避免因自动装配带来的不确定性,适当地结合显式配置更为稳健。
再再来个代码例子举例一下,你应该就会懂了( ̄▽ ̄)/
做一个UserController、UserService、UserDao三层之间的实际场景模拟
创建类UserController
- package com.sakurapaid.spring.iocxml.auto.controller;
-
- public class UserController {
-
- public void conMethod(){
- System.out.println("UserController方法执行了~");
- }
-
- }
创建接口UserService
- package com.sakurapaid.spring.iocxml.auto.service;
-
- public interface UserService {
- public void serMethod();
- }
创建类UserServiceImpl实现接口UserService
- package com.sakurapaid.spring.iocxml.auto.service;
-
- public class UserServiceImpl implements UserService {
- @Override
- public void serMethod() {
- System.out.println("UserService方法执行了~");
- }
- }
创建接口UserDao
- package com.sakurapaid.spring.iocxml.auto.controller;
-
- public class UserController {
-
- public void conMethod();
-
- }
创建类UserDaoImpl实现接口UserDao
- package com.sakurapaid.spring.iocxml.auto.dao;
-
- public class UserDaoImpl implements UserDao {
-
- @Override
- public void method() {
- System.out.println("UserDao方法执行了~");
- }
-
- }
在类UserController中,生成service层对象,设置service属性set方法,调用service层方法
- package com.sakurapaid.spring.iocxml.auto.controller;
-
- import com.sakurapaid.spring.iocxml.auto.service.UserService;
-
- public class UserController {
-
- //生成service层对象
- private UserService userService;
-
- //设置service属性set方法
- public void setUserService(UserService userService)
- {
- this.userService = userService;
- }
-
- public void conMethod(){
- //调用service层方法
- userService.serMethod();
- System.out.println("UserController方法执行了~");
- }
-
- }
在类UserServiceImpl实现类同理
- package com.sakurapaid.spring.iocxml.auto.service;
-
- import com.sakurapaid.spring.iocxml.auto.dao.UserDao;
-
- public class UserServiceImpl implements UserService {
-
- //生成dao层对象
- private UserDao userDao;
- public void setUserDao(UserDao userDao) {
- this.userDao = userDao;
- }
- @Override
- public void serMethod() {
- //调用dao层方法
- userDao.method();
- System.out.println("UserService方法执行了~");
- }
- }
上面的都还是准备工作,现在就实现真正的自动装配
使用bean标签的autowire属性设置自动装配效果
若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null
若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
配置spring bean
- <?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="controller" class="com.sakurapaid.spring.iocxml.auto.controller.UserController"
- autowire="byType">
- </bean>
-
- <bean id="service" class="com.sakurapaid.spring.iocxml.auto.service.UserServiceImpl"
- autowire="byType">
- </bean>
-
- <bean id="dao" class="com.sakurapaid.spring.iocxml.auto.dao.UserDaoImpl"
- autowire="byType">
- </bean>
- </beans>
测试输出
- package com.sakurapaid.spring.iocxml.auto;
-
- import com.sakurapaid.spring.iocxml.auto.controller.UserController;
- import org.junit.jupiter.api.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- public class autoTest {
- @Test
- public void test() {
- ApplicationContext context = new ClassPathXmlApplicationContext("bean-auto.xml");
-
- UserController controller = (UserController) context.getBean("controller");
-
- controller.conMethod();
-
- }
- }

- <?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="controller" class="com.sakurapaid.spring.iocxml.auto.controller.UserController"
- autowire="byName">
- </bean>
-
- <bean id="service" class="com.sakurapaid.spring.iocxml.auto.service.UserServiceImpl"
- autowire="byName">
- </bean>
-
- <bean id="dao" class="com.sakurapaid.spring.iocxml.auto.dao.UserDaoImpl"
- autowire="byName">
- </bean>
- </beans>