跳到主要内容
Spring 框架核心概念与入门使用 | 极客日志
Java java
Spring 框架核心概念与入门使用 综述由AI生成 系统介绍了 Spring 框架的基础知识与核心功能。内容包括 Spring 定义、IoC 控制反转与 DI 依赖注入原理、Bean 的生命周期与作用域。详细讲解了基于 XML 的配置方式,涵盖属性注入、集合注入、外部属性文件引入及自动装配。同时介绍了基于注解的 Bean 管理,如@Component、@Autowired、@Resource 等注解的使用,以及全注解开发模式。通过代码示例帮助读者快速掌握 Spring 入门技能。
CodeArtist 发布于 2026/3/27 更新于 2026/6/5 42 浏览Spring 框架核心概念与入门使用
Spring 概述
1. 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 正式版本。
2. Spring 核心
Spring 指的是 Spring Framework,通常我们称之为 Spring 框架。Spring 框架是一个分层的面向切面的 Java 应用程序的一站式解决框架,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。
Spring 有两个核心模块:IoC 和 AOP。
IoC :Inverse of Control 的简写,为控制反转,指把创建对象交给 Spring 进行管理。
AOP :Aspect Oriented Programming 的简写,为面向切面编程。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
3. Spring Framework 的特点
控制反转 :IoC,反转资源获取方向;把自己创建的资源、向环境索取资源变为环境将资源准备好,我们享受资源注入。
面向切面编程 :AOP,在不修改源代码的基础上增强代码功能。
容器 :Spring IoC 是一个容器,因为它包含并管理组件对象的生命周期;组件享受到了容器化的管理,替程序员屏蔽了组件创建过程中的大量细节,极大降低了使用门槛,大幅度提高了开发效率。
一站式 :在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方库,而且在 Spring 旗下的项目已经覆盖了广泛领域,很多方面的功能性需求可以在 Spring Framework 的基础上全部使用 Spring 来实现。
入门案例
1. 环境要求
JDK:Java 8-15
Spring:5.3.24
2. 构建工程
2.1 构建子工程 first-spring
在父工程中创建子工程 spring-first。
Name 为 spring-first,点击 Finish。
2.2 入门案例
① 在 spring-first/pom.xml 中引入相关依赖,并刷新 Maven
<dependencies >
<dependency >
<groupId > org.springframework</groupId >
<artifactId > spring-context</ >
5.3.24
artifactId
<version >
</version >
</dependency >
</dependencies >
② 在工程中创建包 com.example.spring.begin
public class User {
public void add () {
System.out.println("添加方法..." );
}
}
⑤ 创建 spring 配置文件:resources 目录下创建 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.example.spring.User" > </bean >
</beans >
⑦ 创建测试类 com.example.spring.TestUser 进行测试
public class TestUser {
public static void main (String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean.xml" );
User user = (User) context.getBean("user" );
System.out.println("user = " + user);
user.add();
}
}
2.3 对象存储 存放到容器中,查看源码,DefaultListableBeanFactory.java,第 164 行。
key:唯一标识
value:类的定义(描述信息)
可以查看 BeanDefinition 的源码,有类的描述信息,是否初始化的状态等等。
IoC 容器 IoC 是 Inversion of Control 的简写,译为 控制反转。
Spring 通过 IoC 容器来管理所有的 Java 对象的实例化和初始化,控制着对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。
IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。
1. 控制反转 IoC
控制反转是一种思想
将对象的创建权利交出去,交给第三方容器负责
将对象和对象之间的关系维护权交出去,交给第三方容器负责
如何实现通过依赖注入 DI 的方式实现
2. 依赖注入 DI DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想,是指 Spring 创建对象的过程中,将对象依赖属性通过配置进行注入。
依赖注入常见的实现方式有两种:
set 注入
构造注入
所以 IoC 是一种控制反转的思想,而 DI 是对 IoC 的一种具体实现。
Bean 管理:指 Bean 对象的创建,以及 Bean 对象中属性的赋值(或 Bean 对象之间关系的维护)
3. IoC 容器实现 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 容器对象
4. 基于 XML 管理 bean
4.1 环境准备 ② 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 执行~~" );
}
}
4.2 获取 bean 方式 注意 当根据类型获取 bean 时,要求 IoC 容器中指定类型的 bean 只能有一个,当配置两个时会抛出异常。
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 id ="user" class ="com.example.spring.iocxml.User" > </bean >
public class UserTest {
public static void main (String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean.xml" );
User user1 = (User) context.getBean("user" );
System.out.println("1-根据 id 获取对象:" + user1);
user1.userMethod();
}
}
4.3 基于 setter 依赖注入 类有属性,创建对象过程中,向属性注入具体的值。
方式 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
<bean id ="book" class ="com.example.spring.DI.Book" >
<property name ="bookName" value ="java" > </property >
<property name ="bookAuthor" value ="tedu" > </property >
</bean >
public class BookTest {
public void springSetTest () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-di.xml" );
Book book = context.getBean("book" , Book.class);
System.out.println("book = " + book);
}
}
4.4 基于构造器依赖注入
说明通过构造器方式实现依赖注入
操作步骤说明
创建类,定义属性,生成有参数构造方法
进行 xml 配置
创建测试类测试
① 创建电影信息类 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 id ="film" class ="com.example.spring.DI.Film" >
<constructor-arg name ="title" value ="霸王别姬" > </constructor-arg >
<constructor-arg name ="actor" value ="张国荣" > </constructor-arg >
</bean >
public class FilmTest {
public void FilmConsDITest () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-di.xml" );
Film film = context.getBean("film" , Film.class);
System.out.println("film = " + film);
}
}
4.5 特殊值处理注入
4.5.1 字面量赋值 声明一个变量 number,初始化为 10,此时 number 就不代表字符 number 了,而是作为一个变量的名字。当引用 number 时,实际拿到的结果是 10。而如果 number 是带引号的'number',则它不是一个变量,而代表 number 本身这个字符串。这就是字面量,所以字面量没有引申含义,就是我们看到的这个数据本身。
<property name ="number" value ="1016" > </property >
4.5.2 null 值 使用 <null> 标签,或者 <value> 标签实现注入。
private String description;
<bean id ="film" class ="com.example.spring.DI.Film" >
<constructor-arg name ="title" value ="霸王别姬" > </constructor-arg >
<constructor-arg name ="actor" value ="张国荣" > </constructor-arg >
<constructor-arg name ="description" >
<null > </null >
</constructor-arg >
</bean >
4.5.3 xml 实体
说明 < > 小于号、大于号在 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 >
<constructor-arg name ="description" value ="< 真好看啊电影> " > </constructor-arg >
</bean >
4.5.4 CDATA 区 CDATA 区,是 xml 中一种特有的写法,在 CDATA 区中可以包含特殊符号。
表示方式:<![CDATA[内容]]>,在内容区域可以存放普通字符和特殊符号。
<bean id ="filmCdata" class ="com.example.spring.DI.Film" >
<constructor-arg name ="title" value ="霸王别姬" > </constructor-arg >
<constructor-arg name ="actor" value ="张国荣" > </constructor-arg >
<constructor-arg name ="description" >
<value > <![CDATA[<真好看啊>]]></value >
</constructor-arg >
</bean >
4.6 对象类型属性注入
环境准备准备一个一对多案例,比如部门 Dept 和员工 Emp 是一对多的关系。
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 + '}';
}
}
4.6.1 引用外部 bean 说明:可以通过在当前 bean 标签中通过 ref 属性 引用外部 bean 的方式实现。
示例:通过使用外部 bean 方式,在员工中注入部门对象
① 配置文件 bean-diobj.xml
<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 >
<property name ="dept" ref ="dept1" > </property >
</bean >
public class TestDept {
public void testObjDI () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-diobj.xml" );
Emp emp1 = context.getBean("emp1" , Emp.class);
System.out.println("emp1 = " + emp1);
emp1.work();
}
}
4.6.2 内部 bean 在需要注入对象的 bean 标签中内嵌 对象类型属性的 bean 标签即可。
① bean-diobj.xml 进行属性注入配置
<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 >
public void testObjDi2 () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-diobj.xml" );
Emp emp2 = context.getBean("emp2" , Emp.class);
System.out.println("emp2 = " + emp2);
emp2.work();
}
4.6.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" />
<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();
}
4.7 数组类型属性注入
说明:一个人除了姓名、年龄等属性外,还会有爱好,一个人的爱好可能有多个,可以把多个爱好存入数组中。
创建包:com.example.spring.diarray
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 进行注入
<bean id ="person" class ="com.example.spring.diarray.Person" >
<property name ="name" value ="孙悟空" />
<property name ="age" value ="36" />
<property name ="hobby" >
<array >
<value > 抽烟</value >
<value > 喝酒</value >
<value > 烫头</value >
</array >
</property >
</bean >
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();
}
}
4.8 集合类型属性注入
4.8.1 List 集合属性注入 场景 1:使用 <list> 标签下的 <ref> 子标签和 <value> 子标签实现。
场景 2:使用 <list> 标签下的 <ref> 子标签和子标签实现。ref 标识引用其他的 bean
环境说明:创建老师类 Teacher 和学生类 Student,一个老师可以有多个学生,在老师类中存入所教学生的对象,将其存入 List 集合中。
public class Teacher {
private String tName;
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 + '}' ;
}
}
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 进行注入
<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 >
<bean id ="teacher" class ="com.example.spring.dimap.Teacher" >
<property name ="tName" value ="沙师弟" />
<property name ="studentList" >
<list >
<ref bean ="stu1" />
<ref bean ="stu2" />
</list >
</property >
</bean >
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);
}
}
}
4.8.2 Map 集合属性注入 使用 <map> 标签下的子标签、<entry> 子标签、<key> 子标签 <value> 子标签 <ref> 子标签实现。
<bean id ="xxx" class ="xxx" >
<property name ="xxx" >
<map >
<entry >
<key > <value > xxx</value > </key >
<value > xxx</value >
</entry >
<entry >
<key > <value > xxx</value > </key >
<ref bean ="xxx" > </ref >
</entry >
</map >
</property >
</bean >
说明:使用上述的老师类和学生类,一个学生也可以有多个老师,在学生类 Student 中添加老师的属性,放到 Map 集合中。
private Map<String,String> teacherMap;
<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 > <value > 3333</value > </key >
<value > 大空翼</value >
</entry >
</map >
</property >
</bean >
public void testMap () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-dimap.xml" );
Student student = context.getBean("stuMap" , Student.class);
System.out.println("student = " + student);
}
4.8.3 引用集合类型 bean 注入
说明通过使用 <util:map> 标签实现
使用步骤
<util:map id ="xxx" > </util:map >
<util:list id ="xxx" > </util:list >
<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 集合属性
private List<String> courseList;
② 创建 spring 配置文件:bean-diref.xml,引入 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 >
<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</value > </key >
<value > 王老师</value >
</entry >
</util:map >
<util:list id ="courseList" >
<value > Spring</value >
<value > SpringMVC</value >
<value > MyBatis</value >
</util:list >
public void testRefBean () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-diref.xml" );
Student student = context.getBean("stuUtil" , Student.class);
System.out.println("student = " + student);
}
4.9 p 命名空间 这也是一种注入方式,可以在 xml 中定义命名空间或者叫名称空间,可以简化 xml 代码。
xmlns:p="http://www.springframework.org/schema/p"
<bean id ="studentp" class ="com.example.spring.iocxml.dimap.Student"
p:sid ="100" p:sname ="铁锤妹妹" p:courseList-ref ="courseList" p:teacherMap-ref ="teacherMap" >
public void testRefP () {
ApplicationContext context = new ClassPathXmlApplicationContext ("bean-diref.xml" );
Student studentp = context.getBean("studentp" , Student.class);
System.out.println("studentp = " + studentp);
}
4.10 引入外部属性文件
说明 当前所有的配置和数据都在 xml 文件中,一个文件中有很多 bean,修改和维护起来很不方便,生产环境中会把特定的固定值放到外部文件中,然后引入外部文件进行注入,比如数据库连接信息。
示例 将外部文件中的数据引入 xml 配置文件进行注入
① pom.xml 中引入数据库相关依赖,并刷新 Maven
<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" value ="${jdbc.driver}" > </property >
</bean >
</beans >
④ 创建包 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());
}
}
4.11 bean 的作用域
说明 bean 的作用域,是指在交给 spring 创建 bean 对象时,可以指定是单实例还是多实例,通过 bean 标签中的 scope 属性来指定,默认是单实例。
单实例和多实例
单实例 单实例(Singleton)是指某个类只能创建唯一的一个实例对象,并且该类提供一个全局的访问点(静态方法)来让外界获取这个实例,常常用在那些只需要一个实例来处理所有任务的场景下,例如配置类或数据库连接池等。
多实例 多实例(Multiple Instance)则是指可以在同一个类的定义下,创建多个实例对象。每个对象都是相互独立的,有自己的状态和行为;常常用于需要同时处理多个任务的场景。
在 Spring 中可以通过配置 bean 标签的 scope 属性来指定 bean 的作用域范围,具体如下
取值 含义 创建对象时机 singleton(默认 ) 在 IoC 容器中,这个 bean 的对象为单实例 IoC 容器初始化时 prototype 这个 bean 在 IoC 容器中有多个实例 获取 bean 时
② 创建 spring 的配置文件:bean-scope.xml
<bean id ="sku" class ="com.example.spring.scope.Sku" scope ="singleton" > </bean >
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);
}
4.12 bean 的生命周期
4.12.1 bean 的完整生命周期
实例化阶段(bean 对象创建)在这个阶段中,容器会创建一个 Bean 的实例,并为其分配空间。这个过程可以通过构造方法完成。
属性赋值阶段 在实例化完 Bean 之后,容器会把 Bean 中的属性值注入到 Bean 中,这个过程可以通过 set 方法完成。
初始化阶段(bean 对象初始化)在属性注入完成后,容器会对 Bean 进行一些初始化操作;
初始化之前:bean 的后置处理器可以接收到 bean,此处可以对 bean 做相关操作。
初始化之后:bean 的后置处理器可以接收到 bean,此处可以对 bean 做相关操作。
使用阶段 初始化完成后,Bean 就可以被容器使用了
销毁阶段 容器在关闭时会对所有的 Bean 进行销毁操作,释放资源。
4.12.2 生命周期验证 package com.example.spring.life;
import org.springframework.beans.BeansException;
public class User {
private String username;
public User () {
System.out.println("1-bean 对象创建,调用无参数构造。" );
}
public void initMethod () {
System.out.println("3-bean 对象初始化,调用指定的初始化方法" );
}
public void destoryMethod () {
System.out.println("5-bean 对象销毁,调用指定的销毁方法" );
}
public String getUsername () { return username; }
public void setUsername (String username) {
this .username = username;
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 >
public void testUser () {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("bean-life.xml" );
User user = context.getBean("user" , User.class);
System.out.println("4-bean 对象初始化完成,开发者可以使用了。" );
context.close();
}
④ 后置处理器处理演示,新建类 MyBeanPost
public class MyBeanPost implements 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 id ="myBeanPost" class ="com.example.spring.life.MyBeanPost" > </bean >
4.12.3 bean 生命周期扩展
bean 的初始化和销毁应用场景
后置处理器实现自定义的 Bean 对象处理逻辑,比如在 Bean 实例化之前或者之后对 Bean 对象进行自定义的修改,可以方便地实现自定义逻辑和修改 Bean 对象的行为。
4.13 基于 xml 自动装配
自动装配说明:根据指定的策略,在 IoC 容器中匹配某一个 bean,自动为指定的 bean 中的所依赖的类类型或者接口类型属性赋值。
① 创建包 auto,创建部门和员工的两个 java 类
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; }
}
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
<bean id ="dept" class ="com.example.spring.iocxml.auto.Dept" >
<property name ="dName" value ="技术部" > </property >
</bean >
<bean id ="emp" class ="com.example.spring.iocxml.auto.Emp" autowire ="byType" >
<property name ="eName" value ="步惊云" > </property >
</bean >
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 进行赋值
5 基于注解管理 bean 从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 xml 配置。
Spring 通过注解实现自动装配:
引入依赖
开启组件扫描
使用注解定义 Bean
依赖注入
5.1 创建子工程 子工程:spring-ioc-annotation
在 pom.xml 中添加 springframework 的依赖,刷新 Maven
<dependencies >
<dependency >
<groupId > org.springframework</groupId >
<artifactId > spring-context</artifactId >
<version > 5.3.24</version >
</dependency >
</dependencies >
5.2 开启组件扫描 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" >
<context:component-scan base-package ="com.example.spring" > </context:component-scan >
</beans >
5.3 使用注解定义 Bean 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 相同。
@Controller
public class User {}
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);
}
}
5.4 @Autowired 注入 单独使用@Autowired 注解,默认根据类型装配(byType)
@Autowired 注解有一个 required 属性,默认值是 true,表示在注入的时候要求被注入的 Bean 必须存在,如果不存在则报错。如果 required 属性设置为 false,表示注入的 Bean 存在或者不存在都没关系,存在就注入,不存在也不报错。
5.4.1 属性注入 ① 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 {
@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();
}
}
5.4.2 set 注入
private UserService userService;
@Autowired
public void setUserService (UserService userService) {
this .userService = userService;
}
5.4.3 构造方法注入
private UserService userService;
@Autowired
public UserController (UserService userService) {
this .userService = userService;
}
5.4.4 形参上注入
private UserService userService;
public UserController (@Autowired UserService userService) {
this .userService = userService;
}
5.4.5 只有一个构造函数,无注解
private UserService userService;
public UserController (UserService userService) {
this .userService = userService;
}
5.4.6 @Autowire 注解和@Qualifier 注解联合 ① 再创建一个 UserService 接口的实现类 service.UserServiceImpl2
@Service
public class UserServiceImpl2 implements UserService {
@Override
public void addService () {
System.out.println("service2 is running..." );
}
}
② 测试发现报错
因为 UserService 有两个实现类,而@Autowired 注解根据 byType 定位,所以找到了两个实现类
③ 解决:修改 UserController(使用两个注解)
@Autowired
@Qualifier(value = "userServiceImpl2")
private UserService userService;
5.5 @Resource 注入 @Resource 注解也可以完成属性注入。它和@Autowired 注解的区别如下
@Resource 注解是 JDK 扩展包中的,也就是说属于 JDK 的一部分。所以该解释是标准注解,更加具有通用性,而@Autowired 注解是 Spring 框架自己的。
@Resource 注解默认根据名称装配 byName,未指定 name 时,使用属性名作为 name,通过 name 找不到的话会自动启动通过类型 byType 装配。而@Autowired 注解默认根据类型装配 byType,如果想根据名称匹配,需要配合@Qualifier 注解一起使用。
@Resource 注解用在属性上、setter 方法上
@Autowired 注解用在属性上、setter 方法上、构造方法上、构造方法参数上。
案例演示
① 工程下创建包 resource,和之前一样,创建 controller 和 service 两个包,并创建 UserController 类和 UserService 接口以及该接口的实现类 UserServiceImpl
@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 {
指定@Resource 中的 name,则根据名称装配
未指定 name 时,则根据属性名装配
未指定 name,属性名也不一致,则根据类型装配
5.6 Spring 全注解开发 全注解开发就是不再使用 spring 配置文件了,写一个配置类来代替配置文件。
① 工程下创建包:config,创建类 SpringConfig
@Configuration
@ComponentScan("com.example.spring")
public class SpringConfig {}
public class TestUserControllerAnno {
public static void main (String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext (SpringConfig.class);
UserController controller = context.getBean(UserController.class);
controller.add();
}
}
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online