spring

spring概述
1 spring定义
spring是一款主流的java ee 轻量级开源框架,目的是用于简化java企业级引用的开发难度和开发周期。从简单性、可测试性和松耦合度的角度而言,任何java应用都可以从spring中受益。spring框架提供自己提供功能外,还提供整合其他技术和框架的能力。
spring自诞生以来备受青睐,一直被广大开发人员作为java企业级应用程序开发的首选。时至今日,spring俨然成为了java ee的代名词,成为了构建java ee 应用的事实标准。
自2004年4月,spring1.0 版正式发布以来,spring已经步入到了第6个大版本,即 spring6,以下内容采用spring5.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:java8-15
- spring:5.3.24
2 构建工程
2.1 构建子工程first-spring
在jsd2303-spring中创建子工程 spring-first
new - module

点击 next

name为spring-first,点击 finish

2.2 入门案例
① 在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>② 在工程中创建包 cn.tedu.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="cn.tedu.spring.user"></bean>
</beans>⑦ 创建测试类cn.tedu.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();
}
}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 环境准备
① 创建子工程 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下创建类 cn.tedu.spring.iocxml.user
public class user {
private string username;
private string password;
public void usermethod(){
system.out.println("usermethod执行~~");
}
}4.2 获取bean方式
根据id获取
id属性是bean的唯一标识,所以根据bean标签的id属性可以精确获取到一个组件对象。
① bean.xml
<bean id="user" class="cn.tedu.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();
}
}根据类型获取
user user2 = context.getbean(user.class);
system.out.println("2-根据类型获取bean:" + user2);
user2.usermethod();
根据id和类型获取
user user3 = context.getbean("user", user.class);
system.out.println("3-根据id和类型获取bean:" + user3);
user3.usermethod();
注意
当根据类型获取bean时,要求ioc容器中指定类型的bean只能有一个,当配置两个时会抛出异常
<bean id="user" class="cn.tedu.spring.iocxml.user"></bean> <bean id="user2" class="cn.tedu.spring.iocxml.user"></bean>

4.3 基于setter依赖注入
类有属性,创建对象过程中,向属性注入具体的值
方式1:使用set方法完成(使用xml中的标签实现)
方式2:基于构造器完成
案例
① 创建package名为dibase,创建book类
package cn.tedu.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='" + bookauthor + '\'' +
'}';
}
}② 创建spring配置文件:resources目录下创建 bean-di.xml
<!-- set方法注入 -->
<bean id="book" class="cn.tedu.spring.di.book">
<!--2.使用property标签注入-->
<property name="bookname" value="java"></property>
<property name="bookauthor" value="tedu"></property>
</bean>③ 创建测试类testbook进行测试
public class booktest {
// spring的set方法注入
@test
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='" + actor + '\'' +
'}';
}
}② 在bean-di.xml中进行注入配置
<!-- 构造器注入演示:film类 -->
<bean id="film" class="cn.tedu.spring.di.film">
<constructor-arg name="title" value="霸王别姬"></constructor-arg>
<constructor-arg name="actor" value="张国荣"></constructor-arg>
</bean>③ 创建测试类testfilm测试
public class filmtest {
@test
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);
}
}4.5 特殊值处理注入
4.5.1 字面量赋值
string number = 10;
声明一个变量number,初始化为 10,此时number就不代表字符number了,而是作为一个变量的名字。当引用number时,实际拿到的结果是 10。
而如果number是带引号的 “number” ,则它不是一个变量,而代表 number 本身这个字符串。
这就是字面量,所以字面量没有引申含义,就是我们看到的这个数据本身。
<!-- 使用value属性给bean的属性赋值时,spring会把value的属性值看作是字面量 --> <property name="number" value="1016"></property>
4.5.2 null值
使用 标签,或者 标签 实现注入。
① film类中增加电影描述属性
// 1.电影描述 private string description; // 2.生成对应的 set() get() 方法,重新生成tostring()方法 // 3.重新生成全参构造方法
② bean-di.xml配置文件调整
<!-- 构造器注入演示:film类 -->
<bean id="film" class="cn.tedu.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>③ 执行测试类进行测试
- 课堂练习
- cn.tedu.spring下创建包exercise,在包下创建商品表 product,类属性如下:
- 商品标题:title
- 商品库存:num
- 商品销量:sales
- 商品描述:comment
- 实现 商品product类的创建,setter() getter() tostring(),
- 通过配置文件bean-product.xml
- 通过set方式注入一组数据(商品描述为null值);
- 通过构造参数方式注入一组数据(商品描述为null值);
- 创建测试类testproduct进行测试。
- 练习答案
① product类
public class product {
private string title;
private integer num;
private integer sales;
private string comment;
// 无参构造函数、有参构造函数 setter() getter() tostring()
}
② bean-product.xml
<!-- set方法注入 -->
<bean id="product" class="cn.tedu.spring.exercise.product">
<property name="title" value="手机"></property>
<property name="num" value="100"></property>
<property name="sales" value="1000"></property>
<property name="comment">
<null></null>
</property>
</bean>
<!-- 构造参数方法注入 -->
<bean id="productcons" class="cn.tedu.spring.exercise.product">
<constructor-arg name="title" value="电脑"/>
<constructor-arg name="num" value="2"/>
<constructor-arg name="sales" value="3"/>
<constructor-arg name="comment">
<null></null>
</constructor-arg>
</bean>③ producttest测试类
@test
public void testproduct(){
applicationcontext context = new classpathxmlapplicationcontext("bean-product.xml");
product product = context.getbean("product", product.class);
system.out.println("product = " + product);
}
4.5.3 xml实体
- 说明
- < > 小于号、大于号在xml文档中用来定义标签的开始,具有特殊含义,在注入属性值时不能够随便使用,
- 可以使用xml实体
< >来代替
- 表示方式
普通字符 | xml实体 |
|---|---|
| < | < |
| > | > |
查看示例 bean-di.xml:
<!-- xml实体 -->
<bean id="filmentity" class="cn.tedu.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>4.5.4 cdata区
cdata区,是xml中一种特有的写法,在cdata区中可以包含特殊符号
表示方式:
<![cdata[内容]]> ,在内容区域可以存放普通字符和特殊符号
cdata区存放特殊符号演示
<!-- xml实体-cdata区 -->
<bean id="filmcdata" class="cn.tedu.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>4.6 对象类型属性注入
需要注入的数据类型为对象,而不是一个字面量。
- 环境准备
- 准备一个一对多案例,比如部门dept和员工emp是一对多的关系。
① 创建包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='" + ename + '\'' +
", salary=" + salary +
'}';
}
}4.6.1 引用外部bean
说明:
可以通过在当前bean标签中通过 ref属性引用外部bean的方式实现。
示例:通过使用外部bean方式,在员工中注入部门对象
① 配置文件 bean-diobj.xml
<!--在emp中注入dept
方式1:引用外部bean
1.创建两个类对象:dept 和 emp
2.在emp的bean标签中,通过property标签注入dept的bean
-->
<bean id="dept1" class="cn.tedu.spring.diobj.dept">
<property name="dname" value="开发部"></property>
</bean>
<bean id="emp1" class="cn.tedu.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 {
// 对象类型注入测试用例
@test
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();
}
}4.6.2 内部bean
在需要注入对象的bean标签中内嵌 对象类型属性的 bean标签即可。
内嵌bean
① bean-diobj.xml进行属性注入配置
<!--在emp中注入dept
方式2:引用内部bean
在emp的bean标签中,通过内嵌部门bean标签方式实现
-->
<bean id="emp2" class="cn.tedu.spring.diobj.emp">
<property name="ename" value="张无忌"/>
<property name="salary" value="8000.0"/>
<!--对象注入-->
<property name="dept">
<bean id="dept2" class="cn.tedu.spring.diobj.dept">
<property name="dname" value="销售部"/>
</bean>
</property>
</bean>② 使用测试类测试
// 对象类型注入:内嵌bean
@test
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 级联属性赋值(了解)
可以在标签中给需要注入对象的属性重新赋值!
① 配置文件编写
<!--方式3:级联属性(需要注入的属性)赋值-->
<bean id="dept3" class="cn.tedu.spring.diobj.dept">
<property name="dname" value="市场部"/>
</bean>
<bean id="emp3" class="cn.tedu.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>② 测试类测试
// 对象类型注入:级联属性赋值
@test
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 数组类型属性注入
使用 标签和子标签实现。
说明:一个人除了姓名、年龄等属性外,还会有爱好,一个人的爱好可能有多个,可以把多个爱好存入数组中。
创建包:cn.tedu.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='" + age + '\'' +
", hobby=" + arrays.tostring(hobby) +
'}';
}
}② 新建配置文件:bean-diarray.xml 进行注入
<!-- 创建person对象并注入属性 -->
<bean id="person" class="cn.tedu.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 {
// 数组注入测试用例
@test
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:使用 标签下的 子标签和 子标签实现。
场景2:使用 标签下的 子标签和子标签实现。ref标识引用其他的bean
环境说明:创建老师类student和学生类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='" + course + '\'' +
'}';
}
}④ 创建配置文件:bean-dilistmap.xml 进行注入
<!-- 创建2个student对象,用于teacher对象的注入 -->
<bean id="stu1" class="cn.tedu.spring.dimap.student">
<property name="sname" value="梁山伯"/>
<property name="age" value="43"/>
</bean>
<bean id="stu2" class="cn.tedu.spring.dimap.student">
<property name="sname" value="祝英台"/>
<property name="age" value="33"/>
</bean>
<!-- 创建teacher类的bean对象,并注入属性 -->
<bean id="teacher" class="cn.tedu.spring.dimap.teacher">
<!-- 普通属性注入 -->
<property name="tname" value="沙师弟"/>
<!-- list集合属性注入 -->
<property name="studentlist">
<list>
<ref bean="stu1"/>
<ref bean="stu2"/>
</list>
</property>
</bean>⑤ 测试类testteacher测试
public class testteacher {
@test
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集合属性注入
使用标签下的子标签、子标签、子标签 子标签 子标签实现
<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="cn.tedu.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>③ 创建测试类进行测试 testmap
@test
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注入
- 说明
- 通过使用 标签实现
- 使用步骤
- 在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>使用util标签进入注入
<!-- map集合util标签 --> <util:map id="xxx"></util:map> <!-- list集合util标签 --> <util:list id="xxx"></util:list>
环境准备及操作步骤
添加课程类,一个学生可以上多门课程
① 在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="cn.tedu.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>④ 创建测试方法进行测试
// 引用集合类型bean注入(util)
@test
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代码。
在bean-diref.html中操作
① 在xml配置文件中定义命名空间
xmlns:p="http://www.springframework.org/schema/p"
② 在xml文件进行命名空间属性注入
<!-- p命名空间注入: 注入学生属性 --> <bean id="studentp" class="cn.tedu.spring.iocxml.dimap.student" p:sid="100" p:sname="铁锤妹妹" p:courselist-ref="courselist" p:teachermap-ref="teachermap">
③ 测试
// p命名空间注入测试用例
@test
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
<!-- 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" value="${jdbc.driver}"></property>
</bean>
</beans>④ 创建包jdbc,包中创建测试类 testjdbc
public class testjdbc {
// 外部文件属性引入测试用例
@test
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时 |
案例演示
① 创建包scope,并在包下创建类sku
public class sku {
}② 创建spring的配置文件:bean-scope.xml
<!-- singleton:单实例 --> <!-- 之后改为prototype多实例测试 --> <bean id="sku" class="cn.tedu.spring.scope.sku" scope="singleton"></bean>
③ 创建测试类testorders
@test
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地址不同
4.12 bean的生命周期
是指一个bean对象从创建到销毁的整个过程。
4.12.1 bean的完整生命周期
- 实例化阶段(bean对象创建)
- 在这个阶段中,容器会创建一个bean的实例,并为其分配空间。这个过程可以通过构造方法完成。
- 属性赋值阶段
- 在实例化完bean之后,容器会把bean中的属性值注入到bean中,这个过程可以通过set方法完成。
- 初始化阶段(bean对象初始化)
- 在属性注入完成后,容器会对bean进行一些初始化操作;
- 初始化之前:bean的后置处理器可以接收到bean,此处可以对bean做相关操作。
- 初始化之后:bean的后置处理器可以接收到bean,此处可以对bean做相关操作。
- 使用阶段
- 初始化完成后,bean就可以被容器使用了
- 销毁阶段
- 容器在关闭时会对所有的bean进行销毁操作,释放资源。
4.12.2 生命周期验证
① 创建包life,创建类user
package cn.tedu.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="cn.tedu.spring.iocxml.life.user" scope="singleton"
init-method="initmethod" destroy-method="destroymethod">
<property name="username" value="聂风"></property>
</bean>③ 创建测试类testuser测试
@test
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="cn.tedu.spring.life.mybeanpost"></bean>
⑥ 运行测试类测试
4.12.3 bean生命周期扩展
- bean的初始化和销毁应用场景
- 初始化
- 创建连接池
- 加载资源文件
- 进行数据校验
- 初始化
- 销毁
- 关闭连接池
- 保存数据
- 释放占用的资源
- 后置处理器
- 实现自定义的bean对象处理逻辑,比如在bean实例化之前或者之后对bean对象进行自定义的修改,可以方便地实现自定义逻辑和修改bean对象的行为。
4.13 基于xml自动装配
自动装配说明:
根据指定的策略,在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="cn.tedu.spring.iocxml.auto.dept">
<property name="dname" value="技术部"></property>
</bean>
<!--autowire="bytype" 或者 autowire="byname"-->
<bean id="emp" class="cn.tedu.spring.iocxml.auto.emp" autowire="bytype">
<property name="ename" value="步惊云"></property>
</bean>⑤ 创建测试类测试testauto
@test
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,为属性自动赋值;
1. 如果在ioc中,没有任何一个兼容类型的bean能够为属性赋值,则改属性不装配,默认值为null;
2. 如果在ioc中,有多个兼容类型的bean能够为属性赋值,则抛出异常 nouniquebeandefinitionexception
自动装配方式:byname
byname:将自动装配的属性名,作为bean的id在ioc容器中匹配相对应的bean进行赋值
5 基于注解管理bean
从java5开始,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注解,就将该类装配到容器中。
① 工程下创建包:cn.tedu.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="cn.tedu.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相同。 |
③ 创建user类,并添加注解
// value可以不写,默认为类名首字母小写
//@component(value = "user") // <bean id="user" class="xxx">
//@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);
}
}
5.4 @autowired注入
单独使用@autowired注解,默认根据类型装配(bytype)
@autowired注解有一个required属性,默认值是true,表示在注入的时候要求被注入的bean必须存在,如果不存在则报错。如果required属性设置为false,表示注入的bean存在或者不存在都没关系,存在就注入,不存在也不报错。
5.4.1 属性注入
① cn.tedu.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();
}
}5.4.2 set注入
① 修改usercontroller类
// 方式二:通过set方法注入
private userservice userservice;
@autowired
public void setuserservice(userservice userservice) {
this.userservice = userservice;
}② 测试
5.4.3 构造方法注入
① 修改usercontroller类
// 第三种方式:构造方法注入
private userservice userservice;
@autowired
public usercontroller(userservice userservice) {
this.userservice = userservice;
}② 测试
5.4.4 形参上注入
① 修改usercontroller类
// 第四种方式:形参注入
private userservice userservice;
public usercontroller(@autowired userservice userservice) {
this.userservice = userservice;
}② 测试
5.4.5 只有一个构造函数,无注解
① 修改usercontroller类
// 第五种方式:只有一个有参数构造函数,无注解
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 (使用两个注解)
// 1.第六种方式:根据类型和名称一起注入 @autowired @qualifier(value = "userserviceimpl2") // 类名首字母小写 private userservice userservice; // 2.将构造函数注释
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
② 修改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 {
⑤ 测试
- 指定@resource中的name,则根据名称装配
- 未指定name时,则根据属性名装配
- 未指定name,属性名也不一致,则根据类型装配
5.6 spring全注解开发
全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件。
① 工程下创建包:config,创建类springconfig
// 配置类
@configuration
// 开启组件扫描
@componentscan("cn.tedu.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();
}
}到此这篇关于spring全面详解-最全最详细的spring基本认识和入门使用的文章就介绍到这了,更多相关spring内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论