Spring 框架核心概念与入门使用
系统介绍了 Spring 框架的基础知识与核心功能。内容包括 Spring 定义、IoC 控制反转与 DI 依赖注入原理、Bean 的生命周期与作用域。详细讲解了基于 XML 的配置方式,涵盖属性注入、集合注入、外部属性文件引入及自动装配。同时介绍了基于注解的 Bean 管理,如@Component、@Autowired、@Resource 等注解的使用,以及全注解开发模式。通过代码示例帮助读者快速掌握 Spring 入门技能。

系统介绍了 Spring 框架的基础知识与核心功能。内容包括 Spring 定义、IoC 控制反转与 DI 依赖注入原理、Bean 的生命周期与作用域。详细讲解了基于 XML 的配置方式,涵盖属性注入、集合注入、外部属性文件引入及自动装配。同时介绍了基于注解的 Bean 管理,如@Component、@Autowired、@Resource 等注解的使用,以及全注解开发模式。通过代码示例帮助读者快速掌握 Spring 入门技能。

Spring 是一款主流的 Java EE 轻量级开源框架,目的是用于简化 Java 企业级应用的开发难度和开发周期。从简单性、可测试性和松耦合度的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架提供自己功能外,还提供整合其他技术和框架的能力。
Spring 自诞生以来备受青睐,一直被广大开发人员作为 Java 企业级应用程序开发的首选。时至今日,Spring 俨然成为了 Java EE 的代名词,成为了构建 Java EE 应用的事实标准。
自 2004 年 4 月,Spring 1.0 版正式发布以来,Spring 已经步入到了第 6 个大版本,即 Spring 6,以下内容采用 Spring 5.3.24 正式版本。
Spring 指的是 Spring Framework,通常我们称之为 Spring 框架。Spring 框架是一个分层的面向切面的 Java 应用程序的一站式解决框架,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。
Spring 有两个核心模块:IoC 和 AOP。
在父工程中创建子工程 spring-first。 Name 为 spring-first,点击 Finish。
① 在 spring-first/pom.xml 中引入相关依赖,并刷新 Maven
<dependencies>
<!-- spring context 依赖 当引入此依赖后,表示将 Spring 的基础依赖引入了 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.24</version>
</dependency>
</dependencies>
② 在工程中创建包 com.example.spring.begin
③ 创建类 User
④ User 类中定义方法
public class User {
public void add() {
System.out.println("添加方法...");
}
}
⑤ 创建 spring 配置文件:resources 目录下创建 bean.xml
⑥ 在 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">
<!-- 完成 user 对象创建 id 属性:唯一标识 class 属性:要创建的对象所在类的绝对路径 -->
<bean id="user" class="com.example.spring.User"></bean>
</beans>
⑦ 创建测试类 com.example.spring.TestUser 进行测试
public class TestUser {
public static void main(String[] args) {
// 1. 加载 spring 配置文件,进行对象创建
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 2. 获取 spring 创建好的对象
User user = (User) context.getBean("user");
// 3. 使用对象调用方法测试
System.out.println("user = " + user);
user.add();
}
}
存放到容器中,查看源码,DefaultListableBeanFactory.java,第 164 行。 key:唯一标识 value:类的定义(描述信息) 可以查看 BeanDefinition 的源码,有类的描述信息,是否初始化的状态等等。
IoC 是 Inversion of Control 的简写,译为 控制反转。 Spring 通过 IoC 容器来管理所有的 Java 对象的实例化和初始化,控制着对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。 IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。
DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想,是指 Spring 创建对象的过程中,将对象依赖属性通过配置进行注入。 依赖注入常见的实现方式有两种:
Spring 中的 IoC 容器就是 IoC 思想的一个落地产品实现。IoC 容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建 IoC 容器,Spring 提供了 IoC 容器的两种实现方式。
① BeanFactory 这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。
② ApplicationContext BeanFactory 的子接口,提供了更多高级特性,面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext,而不是底层的 BeanFactory。
③ ApplicationContext 的主要实现类
| 类型 | 说明 |
|---|---|
| ClassPathXmlApplicationContext | 通过读取类路径下的 xml 格式配置文件创建 IoC 容器对象 |
| FileSystemApplicationContext | 通过文件系统路径读取 xml 格式配置文件创建 IoC 容器对象 |
① 创建子工程 spring-ioc-xml
② pom.xml 中引入 spring 依赖,并刷新 Maven
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.24</version>
</dependency>
</dependencies>
③ 创建 spring 配置文件:resources/bean.xml
④ 在工程目录 java 下创建类 com.example.spring.iocxml.User
public class User {
private String username;
private String password;
public void userMethod() {
System.out.println("userMethod 执行~~");
}
}
注意当根据类型获取 bean 时,要求 IoC 容器中指定类型的 bean 只能有一个,当配置两个时会抛出异常。
根据 id 和类型获取
User user3 = context.getBean("user", User.class);
System.out.println("3-根据 id 和类型获取 bean:" + user3);
user3.userMethod();
根据类型获取
User user2 = context.getBean(User.class);
System.out.println("2-根据类型获取 bean:" + user2);
user2.userMethod();
根据 id 获取 id 属性是 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。
① bean.xml
<bean id="user" class="com.example.spring.iocxml.User"></bean>
② 创建测试类 UserTest
public class UserTest {
public static void main(String[] args) {
// 1. 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据 id 获取 bean
User user1 = (User) context.getBean("user");
System.out.println("1-根据 id 获取对象:" + user1);
user1.userMethod();
}
}
类有属性,创建对象过程中,向属性注入具体的值。 方式 1:使用 set 方法完成(使用 xml 中的标签实现) 方式 2:基于构造器完成
案例 ① 创建 Package 名为 dibase,创建 Book 类
package com.example.spring.DI;
public class Book {
private String bookName;
private String bookAuthor;
// 无参构造函数
public Book() {}
// 全参构造函数
public Book(String bookName, String bookAuthor) {
this.bookName = bookName;
this.bookAuthor = bookAuthor;
}
public String getBookName() { return bookName; }
public void setBookName(String bookName) { this.bookName = bookName; }
public String getBookAuthor() { return bookAuthor; }
public void setBookAuthor(String bookAuthor) { this.bookAuthor = bookAuthor; }
@Override
public String toString() {
return "Book{" + "bookName='" + bookName + '\'' + ",+ bookAuthor + '\'' + '}';
}
}
② 创建 spring 配置文件:resources 目录下创建 bean-di.xml
<!-- set 方法注入 -->
<bean id="book" class="com.example.spring.DI.Book">
<!-- 2. 使用 property 标签注入 -->
<property name="bookName" value="java"></property>
<property name="bookAuthor" value="tedu"></property>
</bean>
③ 创建测试类 TestBook 进行测试
public class BookTest {
// spring 的 set 方法注入
public void springSetTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("book", Book.class);
System.out.println("book = " + book);
}
}
① 创建电影信息类 Film,定义属性并生成全参构造方法
public class Film {
// 电影名称、主演
private String title;
private String actor;
// 全参构造
public Film(String title, String actor) {
System.out.println("Film 的有参构造已经执行~~");
this.title = title;
this.actor = actor;
}
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getActor() { return actor; }
public void setActor(String actor) { this.actor = actor; }
@Override
public String toString() {
return "Film{" + "title='" + title + '\'' + ",+ actor + '\'' + '}';
}
}
② 在 bean-di.xml 中进行注入配置
<!-- 构造器注入演示:Film 类 -->
<bean id="film" class="com.example.spring.DI.Film">
<constructor-arg name="title" value="霸王别姬"></constructor-arg>
<constructor-arg name="actor" value="张国荣"></constructor-arg>
</bean>
③ 创建测试类 TestFilm 测试
public class FilmTest {
public void FilmConsDITest() {
// 1. 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
// 2. 获取指定 bean
Film film = context.getBean("film", Film.class);
// 3. 输出测试
System.out.println("film = " + film);
}
}
声明一个变量 number,初始化为 10,此时 number 就不代表字符 number 了,而是作为一个变量的名字。当引用 number 时,实际拿到的结果是 10。而如果 number 是带引号的'number',则它不是一个变量,而代表 number 本身这个字符串。这就是字面量,所以字面量没有引申含义,就是我们看到的这个数据本身。
<!-- 使用 value 属性给 bean 的属性赋值时,spring 会把 value 的属性值看作是字面量 -->
<property name="number" value="1016"></property>
使用 <null> 标签,或者 <value> 标签实现注入。
① Film 类中增加电影描述属性
// 1. 电影描述
private String description;
// 2. 生成对应的 set() get() 方法,重新生成 toString() 方法
// 3. 重新生成全参构造方法
② bean-di.xml 配置文件调整
<!-- 构造器注入演示:Film 类 -->
<bean id="film" class="com.example.spring.DI.Film">
<constructor-arg name="title" value="霸王别姬"></constructor-arg>
<constructor-arg name="actor" value="张国荣"></constructor-arg>
<!-- 电影描述注入空值 null -->
<constructor-arg name="description">
<null></null>
</constructor-arg>
</bean>
③ 执行测试类进行测试
< > 来代替| 普通字符 | xml 实体 |
|---|---|
| < | < |
| > | > |
查看示例 bean-di.xml:
<!-- xml 实体 -->
<bean id="filmEntity" class="com.example.spring.DI.Film">
<constructor-arg name="title" value="霸王别姬"></constructor-arg>
<constructor-arg name="actor" value="张国荣"></constructor-arg>
<!-- xml 实体表示 -->
<constructor-arg name="description" value="<真好看啊电影>"></constructor-arg>
</bean>
CDATA 区,是 xml 中一种特有的写法,在 CDATA 区中可以包含特殊符号。
表示方式:<![CDATA[内容]]>,在内容区域可以存放普通字符和特殊符号。
CDATA 区存放特殊符号演示
<!-- xml 实体-CDATA 区 -->
<bean id="filmCdata" class="com.example.spring.DI.Film">
<constructor-arg name="title" value="霸王别姬"></constructor-arg>
<constructor-arg name="actor" value="张国荣"></constructor-arg>
<!-- xml 实体表示 -->
<constructor-arg name="description">
<!-- CDATA 区存放数据,可通过 CD + Tab 键自动补全格式 -->
<value><![CDATA[<真好看啊>]]></value>
</constructor-arg>
</bean>
需要注入的数据类型为对象,而不是一个字面量。
① 创建包 diobj,并创建部门类 Dept
public class Dept {
// 部门名称
private String dName;
// 定义方法,用于测试输出
public void deptFunc() {
System.out.println("Dept 部门名称:" + dName);
}
public void setdName(String dName) { this.dName = dName; }
public String getdName() { return dName; }
@Override
public String toString() {
return "Dept{" + "dName='" + dName + '\'' + '}';
}
}
② 创建员工类 Emp,创建 setter() getter() 和 toString() 方法
public class Emp {
// 员工所属部门的对象、姓名、工资
private Dept dept;
private String eName;
private Double salary;
// 定义方法测试
public void work() {
System.out.println(eName + "薪资:" + salary);
dept.deptFunc();
}
public void setDept(Dept dept) { this.dept = dept; }
public void seteName(String eName) { this.eName = eName; }
public void setSalary(Double salary) { this.salary = salary; }
public Dept getDept() { return dept; }
public String geteName() { return eName; }
public Double getSalary() { return salary; }
@Override
public String toString() {
return "Emp{" + "dept=" + dept + ",+ eName + '\'' + ", salary=" + salary + '}';
}
}
说明:可以通过在当前 bean 标签中通过 ref 属性引用外部 bean 的方式实现。
示例:通过使用外部 bean 方式,在员工中注入部门对象 ① 配置文件 bean-diobj.xml
<!-- 在 Emp 中注入 Dept 方式 1:引用外部 bean 1.创建两个类对象:dept 和 emp 2.在 emp 的 bean 标签中,通过 property 标签注入 dept 的 bean -->
<bean id="dept1" class="com.example.spring.diobj.Dept">
<property name="dName" value="开发部"></property>
</bean>
<bean id="emp1" class="com.example.spring.diobj.Emp">
<!-- 普通属性注入 -->
<property name="eName" value="张三丰"></property>
<property name="salary" value="50000.0"></property>
<!-- 对象类型注入,使用 ref 属性 -->
<property name="dept" ref="dept1"></property>
</bean>
② 创建测试类测试 TestDept
public class TestDept {
// 对象类型注入测试用例
public void testObjDI() {
// 1. 加载 xml 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
// 2. 获取 bean 对象
Emp emp1 = context.getBean("emp1", Emp.class);
// 3. 测试 (调用员工 emp 对象的方法)
System.out.println("emp1 = " + emp1);
emp1.work();
}
}
在需要注入对象的 bean 标签中内嵌 对象类型属性的 bean 标签即可。
① bean-diobj.xml 进行属性注入配置
<!-- 在 Emp 中注入 Dept 方式 2:引用内部 bean 在 emp 的 bean 标签中,通过内嵌部门 bean 标签方式实现 -->
<bean id="emp2" class="com.example.spring.diobj.Emp">
<property name="eName" value="张无忌"/>
<property name="salary" value="8000.0"/>
<!-- 对象注入 -->
<property name="dept">
<bean id="dept2" class="com.example.spring.diobj.Dept">
<property name="dName" value="销售部"/>
</bean>
</property>
</bean>
② 使用测试类测试
// 对象类型注入:内嵌 bean
public void testObjDi2() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
Emp emp2 = context.getBean("emp2", Emp.class);
System.out.println("emp2 = " + emp2);
emp2.work();
}
可以在标签中给需要注入对象的属性重新赋值!
① 配置文件编写
<!-- 方式 3:级联属性 (需要注入的属性) 赋值 -->
<bean id="dept3" class="com.example.spring.diobj.Dept">
<property name="dName" value="市场部"/>
</bean>
<bean id="emp3" class="com.example.spring.diobj.Emp">
<!-- 普通属性注入 -->
<property name="eName" value="赵敏"/>
<property name="salary" value="5000.0"/>
<!-- 对象类型注入 -->
<property name="dept" ref="dept3"/>
<!-- 级联属性 (Dept) 赋值 -->
<property name="dept.dName" value="客服部"></property>
</bean>
② 测试类测试
// 对象类型注入:级联属性赋值
public void testObjDi3() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diobj.xml");
Emp emp3 = context.getBean("emp3", Emp.class);
System.out.println("emp3 = " + emp3);
emp3.work();
}
使用 <array> 标签和子标签实现。
说明:一个人除了姓名、年龄等属性外,还会有爱好,一个人的爱好可能有多个,可以把多个爱好存入数组中。
创建包:com.example.spring.diarray
① 在 diarray 包中创建类:Person
public class Person {
// 姓名、年龄、爱好
private String name;
private String age;
private String[] hobby;
// 定义测试方法
public void run() {
System.out.println("Persen is running...");
// 打印数组测试
System.out.println(Arrays.toString(hobby));
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getAge() { return age; }
public void setAge(String age) { this.age = age; }
public String[] getHobby() { return hobby; }
public void setHobby(String[] hobby) { this.hobby = hobby; }
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ",+ age + '\'' + ", hobby=" + Arrays.toString(hobby) + '}';
}
}
② 新建配置文件:bean-diarray.xml 进行注入
<!-- 创建 Person 对象并注入属性 -->
<bean id="person" class="com.example.spring.diarray.Person">
<!-- 普通属性注入 -->
<property name="name" value="孙悟空"/>
<property name="age" value="36"/>
<!-- 数组属性注入,使用<array>标签 -->
<property name="hobby">
<array>
<value>抽烟</value>
<value>喝酒</value>
<value>烫头</value>
</array>
</property>
</bean>
③ 编写测试类 TestPerson 测试
public class TestPerson {
// 数组注入测试用例
public void testArray() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diarray.xml");
Person person = context.getBean("person", Person.class);
System.out.println("person = " + person);
person.run();
}
}
场景 1:使用 <list> 标签下的 <ref> 子标签和 <value> 子标签实现。
场景 2:使用 <list> 标签下的 <ref> 子标签和子标签实现。ref 标识引用其他的 bean
环境说明:创建老师类 Teacher 和学生类 Student,一个老师可以有多个学生,在老师类中存入所教学生的对象,将其存入 List 集合中。
环境准备
① 创建包 dimap
② Teacher 类
public class Teacher {
// 老师姓名
private String tName;
// 老师所教学生的对象,放到 List 集合中
private List<Student> studentList;
public String gettName() { return tName; }
public void settName(String tName) { this.tName = tName; }
public List<Student> getStudentList() { return studentList; }
public void setStudentList(List<Student> studentList) { this.studentList = studentList; }
@Override
public String toString() {
return "Teacher{" + "tName='" + tName + '\'' + ", studentList=" + studentList + '}';
}
}
③ Student 类
public class Student {
// 学生姓名、年龄
private String sName;
private String age;
public String getsName() { return sName; }
public void setsName(String sName) { this.sName = sName; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
@Override
public String toString() {
return "Student{" + "sName='" + sName + '\'' + ",+ course + '\'' + '}';
}
}
④ 创建配置文件:bean-dilistmap.xml 进行注入
<!-- 创建 2 个 Student 对象,用于 Teacher 对象的注入 -->
<bean id="stu1" class="com.example.spring.dimap.Student">
<property name="sName" value="梁山伯"/>
<property name="age" value="43"/>
</bean>
<bean id="stu2" class="com.example.spring.dimap.Student">
<property name="sName" value="祝英台"/>
<property name="age" value="33"/>
</bean>
<!-- 创建 Teacher 类的 bean 对象,并注入属性 -->
<bean id="teacher" class="com.example.spring.dimap.Teacher">
<!-- 普通属性注入 -->
<property name="tName" value="沙师弟"/>
<!-- List 集合属性注入 -->
<property name="studentList">
⑤ 测试类 TestTeacher 测试
public class TestTeacher {
public void testListMap() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-dilistmap.xml");
Teacher teacher = context.getBean("teacher", Teacher.class);
System.out.println("teacher = " + teacher);
List<Student> list = teacher.getStudentList();
for (Student student : list) {
System.out.println(student);
}
}
}
使用 <map> 标签下的子标签、<entry> 子标签、<key> 子标签 <value> 子标签 <ref> 子标签实现。
<bean id="xxx" class="xxx">
<property name="xxx">
<map>
<!-- 第 1 条数据 - 字面量值演示 -->
<entry>
<key><value>xxx</value></key>
<value>xxx</value>
</entry>
<!-- 第 2 条数据 - 对象演示 -->
<entry>
<key><value>xxx</value></key>
<ref bean="xxx"></ref>
</entry>
</map>
</property>
</bean>
说明:使用上述的老师类和学生类,一个学生也可以有多个老师,在学生类 Student 中添加老师的属性,放到 Map 集合中。
① 调整 Student 类
// 1. 学生的老师:可以有多个,放到 Map 集合中
private Map<String,String> teacherMap;
// 2. 生成 setter() getter() 方法,重新生成 toString() 方法
② 创建配置文件:bean-dimap.xml
<!-- Map 集合属性注入 -->
<bean id="stuMap" class="com.example.spring.dilistmap.Student">
<property name="sName" value="步惊云"/>
<property name="age" value="36"/>
<property name="teacherMap">
<map>
<entry>
<key><value>1111</value></key>
<value>雄霸</value>
</entry>
<entry>
<key><value>2222</value></key>
<value>断浪</value>
</entry>
<entry>
<key><>3333
大空翼
③ 创建测试类进行测试 TestMap
public void testMap() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-dimap.xml");
Student student = context.getBean("stuMap", Student.class);
System.out.println("student = " + student);
}
<util:map> 标签实现使用 util 标签进入注入
<!-- Map 集合 util 标签 -->
<util:map id="xxx"></util:map>
<!-- List 集合 util 标签 -->
<util:list id="xxx"></util:list>
在 xml 配置文件中引入 util 约束
<beans 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"></beans>
环境准备及操作步骤 添加课程类,一个学生可以上多门课程
① 在 Student 类中添加 List 集合属性
// 1. 一个学生可以上多门课程,把课程名称放到 List 集合中
private List<String> courseList;
// 2. 生成 get 和 set 方法
// 3. 重新生成 toString() 方法
② 创建 spring 配置文件:bean-diref.xml,引入 util 约束
<!-- 添加 3 行带有 util 的配置 -->
<?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"></beans>
③ 配置 xml 文件完成注入
<!-- 引用集合类型 bean 注入 -->
<bean id="stuUtil" class="com.example.spring.dilistmap.Student">
<property name="sName" value="孔慈"/>
<property name="age" value="36"/>
<property name="teacherMap" ref="teacherMap"></property>
<property name="courseList" ref="courseList"></property>
</bean>
<util:map id="teacherMap">
<entry>
<key><value>10000</value></key>
<value>小泽老师</value>
</entry>
<entry>
<key><value>10001
王老师
Spring
SpringMVC
MyBatis
④ 创建测试方法进行测试
// 引用集合类型 bean 注入(util)
public void testRefBean() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diref.xml");
Student student = context.getBean("stuUtil", Student.class);
System.out.println("student = " + student);
}
这也是一种注入方式,可以在 xml 中定义命名空间或者叫名称空间,可以简化 xml 代码。
① 在 xml 配置文件中定义命名空间
xmlns:p="http://www.springframework.org/schema/p"
② 在 xml 文件进行命名空间属性注入
<!-- p 命名空间注入:注入学生属性 -->
<bean id="studentp" class="com.example.spring.iocxml.dimap.Student"
p:sid="100" p:sname="铁锤妹妹" p:courseList-ref="courseList" p:teacherMap-ref="teacherMap">
③ 测试
// p 命名空间注入测试用例
public void testRefP() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diref.xml");
Student studentp = context.getBean("studentp", Student.class);
System.out.println("studentp = " + studentp);
}
① pom.xml 中引入数据库相关依赖,并刷新 Maven
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!-- 数据源,连接池依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
② resources 目录下创建外部属性文件,一般为 properties 格式,定义数据库信息,比如:jdbc.properties
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.driver=com.mysql.cj.jdbc.Driver
③ 创建 spring 配置文件 bean-jdbc.xml,引入 context 的命名空间 使用 context 可以为 XML 外部实体注入定义,使得解析器在解析 XML 文档时可以正确地识别外部实体
<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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 引入外部属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 完成数据库信息注入 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" =>
④ 创建包 jdbc,包中创建测试类 TestJdbc
public class TestJdbc {
// 外部文件属性引入测试用例
public void demo02() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-jdbc.xml");
DruidDataSource druidDataSource = context.getBean("druidDataSource", DruidDataSource.class);
System.out.println(druidDataSource.getUrl());
}
}
在 Spring 中可以通过配置 bean 标签的 scope 属性来指定 bean 的作用域范围,具体如下
| 取值 | 含义 | 创建对象时机 |
|---|---|---|
| singleton(默认) | 在 IoC 容器中,这个 bean 的对象为单实例 | IoC 容器初始化时 |
| prototype | 这个 bean 在 IoC 容器中有多个实例 | 获取 bean 时 |
案例演示
① 创建包 scope,并在包下创建类 Sku
public class Sku {}
② 创建 spring 的配置文件:bean-scope.xml
<!-- singleton:单实例 -->
<!-- 之后改为 prototype 多实例测试 -->
<bean id="sku" class="com.example.spring.scope.Sku" scope="singleton"></bean>
③ 创建测试类 TestOrders
public void testOrders() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-scope.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("orders = " + orders);
Orders orders1 = context.getBean("orders", Orders.class);
System.out.println("orders1 = " + orders1);
}
// 单实例,sku1 和 sku2 地址相同
// 多实例,sku1 和 sku2 地址不同
是指一个 bean 对象从创建到销毁的整个过程。
① 创建包 life,创建类 User
package com.example.spring.life;
import org.springframework.beans.BeansException;
public class User {
private String username;
// 1. 无参数构造
public User() {
System.out.println("1-bean 对象创建,调用无参数构造。");
}
// 3. 初始化阶段
public void initMethod() {
System.out.println("3-bean 对象初始化,调用指定的初始化方法");
}
// 5. 销毁阶段
public void destoryMethod() {
System.out.println("5-bean 对象销毁,调用指定的销毁方法");
}
public String getUsername() { return username; }
public void setUsername(String username) {
this.username = username;
// 2. 给 bean 对象属性赋值
System.out.println("2-通过 set 方法给 bean 对象赋值。");
}
@Override
public String toString() {
return "User{" + "username='" + username + '\'' + '}';
}
}
② 创建 spring 配置文件 bean-life.xml
<bean id="user" class="com.example.spring.iocxml.life.User" scope="singleton"
init-method="initMethod" destroy-method="destroyMethod">
<property name="username" value="聂风"></property>
</bean>
③ 创建测试类 TestUser 测试
public void testUser() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");
User user = context.getBean("user", User.class);
// 4.bean 对象初始化完成,可以使用
System.out.println("4-bean 对象初始化完成,开发者可以使用了。");
// 销毁 bean
context.close();
}
④ 后置处理器处理演示,新建类 MyBeanPost
public class MyBeanPost implements BeanPostProcessor {
// BeanPostProcessor 接口
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3 之前:bean 后置处理器,在初始化之前执行。" + beanName + ":" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3 之后:bean 后置处理器,在初始化之后执行。" + beanName + ":" + bean);
return bean;
}
}
⑤ 在 spring 的配置文件 bean-life.xml 中进行后置处理器配置
<!-- bean 的后置处理器需要放到 IoC 容器中才能生效 -->
<bean id="myBeanPost" class="com.example.spring.life.MyBeanPost"></bean>
⑥ 运行测试类测试
自动装配说明:根据指定的策略,在 IoC 容器中匹配某一个 bean,自动为指定的 bean 中的所依赖的类类型或者接口类型属性赋值。
环境准备
① 创建包 auto,创建部门和员工的两个 java 类
② 部门类 Dept
public class Dept {
private String dName;
@Override
public String toString() {
return "Dept{" + "dName='" + dName + '\'' + '}';
}
public String getdName() { return dName; }
public void setdName(String dName) { this.dName = dName; }
}
③ 员工类 Emp
public class Emp {
private String eName;
private Dept dept;
@Override
public String toString() {
return "Emp{" + "eName='" + eName + '\'' + ", dept=" + dept + '}';
}
public String geteName() { return eName; }
public void seteName(String eName) { this.eName = eName; }
public Dept getDept() { return dept; }
public void setDept(Dept dept) { this.dept = dept; }
}
④ 创建 spring 配置文件 bean-auto.xml
<!-- 通过 byType 和 byName 自动装配 -->
<bean id="dept" class="com.example.spring.iocxml.auto.Dept">
<property name="dName" value="技术部"></property>
</bean>
<!-- autowire="byType" 或者 autowire="byName" -->
<bean id="emp" class="com.example.spring.iocxml.auto.Emp" autowire="byType">
<property name="eName" value="步惊云"></property>
</bean>
⑤ 创建测试类测试 TestAuto
public void testAuto() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-auto.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println("emp = " + emp);
}
使用 bean 标签的 autowire 属性设置自动装配效果; 自动装配方式:byType byType: 根据类型匹配 IoC 容器中的某个兼容类型的 bean,为属性自动赋值;
- 如果在 IoC 中,没有任何一个兼容类型的 bean 能够为属性赋值,则改属性不装配,默认值为 null;
- 如果在 IoC 中,有多个兼容类型的 bean 能够为属性赋值,则抛出异常 NoUniqueBeanDefinitionException
自动装配方式:byName byName:将自动装配的属性名,作为 bean 的 id 在 IoC 容器中匹配相对应的 bean 进行赋值
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 xml 配置。 Spring 通过注解实现自动装配:
子工程:spring-ioc-annotation 在 pom.xml 中添加 springframework 的依赖,刷新 Maven
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.24</version>
</dependency>
</dependencies>
Spring 默认不使用注解装配 Bean,因此需要在 Spring 的 xml 配置中,通过 context:component-scan 元素开启 Spring Beans 的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了@Component 注解,就将该类装配到容器中。
① 工程下创建包:com.example.spring.bean
② resources 目录下创建 spring 配置文件 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 2. 开启组件扫描,让 spring 可以通过注解方式实现 bean 管理,包括创建对象、属性注入 -->
<!-- base-package:扫描哪个包中的注解,在 cn.tedu 的包或者子包中建了类,在 类上、属性上、方法上加了 spring 的@Component 注解,这里就能扫描到 -->
<context:component-scan base-package="com.example.spring"></context:component-scan>
</beans>
Spring 提供了以下多个注解,这些注解可以直接标注在 java 类上,将它们定义成 Spring Bean。
| 注解 | 说明 |
|---|---|
| @Component | 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅标识容器中的一个组件(Bean),并且可以作用在任何层次,例如 Service 层、Dao 层等,使用时只需将该注解标注在相应的类上即可。 |
| @Respository | 该注解用于数据访问层(Dao 层)的类标识为 Spring 中的 Bean,功能与@Component 相同。 |
| @Service | 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与@Component 相同。 |
| @Controller | 该注解通常作用在控制层(如 SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与@Component 相同。 |
③ 创建 User 类,并添加注解
// value 可以不写,默认为类名首字母小写
//@Component(value = "user") // <bean>
//@Repository
//@Service
@Controller
public class User {}
④ 创建测试类测试 TestUser
public class TestUser {
@Test
public void testUser() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
System.out.println("user = " + user);
}
}
单独使用@Autowired 注解,默认根据类型装配(byType) @Autowired 注解有一个 required 属性,默认值是 true,表示在注入的时候要求被注入的 Bean 必须存在,如果不存在则报错。如果 required 属性设置为 false,表示注入的 Bean 存在或者不存在都没关系,存在就注入,不存在也不报错。
① com.example.spring 下创建包 autowired,并在 autowired 下创建两个包:controller 包 和 service 包
② 控制器层 controller.UserController
public class UserController {
private UserService userService;
public void addController() {
System.out.println("controller is running...");
userService.addService();
}
}
③ 服务层 service.UserService 接口
public interface UserService {
public void addService();
}
④ 服务层 service.UserServiceImpl 接口的实现类
public class UserServiceImpl implements UserService {
@Override
public void addService() {
System.out.println("service is running...");
}
}
⑤ 在 UserController 和 UserSerivceImpl 中添加@Controller 注解和@Service 注解
⑥ 在 UserController 中注入 UserServiceImpl
@Controller
public class UserController {
// 注入 service
// 第一种方式:属性注入
@Autowired
// 根据类型找到对象,完成注入
private UserService userService;
}
⑦ 测试类测试 autowired.TestUserController
public class TestUserController {
@Test
public void testUserController() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserController controller = context.getBean(UserController.class);
controller.addController();
}
}
① 修改 UserController 类
// 方式二:通过 set 方法注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
② 测试
① 修改 UserController 类
// 第三种方式:构造方法注入
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
② 测试
① 修改 UserController 类
// 第四种方式:形参注入
private UserService userService;
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
② 测试
① 修改 UserController 类
// 第五种方式:只有一个有参数构造函数,无注解
private UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
② 测试
① 再创建一个 UserService 接口的实现类 service.UserServiceImpl2
@Service
public class UserServiceImpl2 implements UserService {
@Override
public void addService() {
System.out.println("service2 is running...");
}
}
② 测试发现报错 因为 UserService 有两个实现类,而@Autowired 注解根据 byType 定位,所以找到了两个实现类
③ 解决:修改 UserController(使用两个注解)
// 1. 第六种方式:根据类型和名称一起注入
@Autowired
@Qualifier(value = "userServiceImpl2") // 类名首字母小写
private UserService userService;
// 2. 将构造函数注释
@Resource 注解也可以完成属性注入。它和@Autowired 注解的区别如下
案例演示 ① 工程下创建包 resource,和之前一样,创建 controller 和 service 两个包,并创建 UserController 类和 UserService 接口以及该接口的实现类 UserServiceImpl
② 修改 UserController
@Controller("myUserController")
public class UserController {
// 根据名称进行注入
@Resource(name="myUserService")
private UserService userService;
public void add() {
System.out.println("controller...");
userService.add();
}
}
③ 修改 ServiceControllerImpl1
@Service("myUserService")
public class UserServiceImpl implements UserService {
⑤ 测试
全注解开发就是不再使用 spring 配置文件了,写一个配置类来代替配置文件。
① 工程下创建包:config,创建类 SpringConfig
// 配置类
@Configuration
// 开启组件扫描
@ComponentScan("com.example.spring")
public class SpringConfig {}
② 在 resource 下创建测试类进行测试
public class TestUserControllerAnno {
public static void main(String[] args) {
// 加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserController controller = context.getBean(UserController.class);
controller.add();
}
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online