Spring6 介绍:
- 发布时间:2022年11月
- Spring 框架是一款优秀的轻量级开源框架,为了解决企业应用开发的复杂性而出现
- Spring 框架的用途:服务器端的开发
- 特点:简单性、可测试性、松耦合性
学习 Spring6 的前置知识:
- Java 基础知识(反射)
- Java 注解
- XML
- Maven
一、Spring 概述
1.1 Spring 是什么?
Spring 是一款主流的 Java EE 轻量级开源框架。
Spring 的作用:用于简化 Java 企业级应用的开发难度和开发周期
开始发布时间:2004年4月,Spring 1.0 版本正式发布。
1.2 Spring 广义和狭义划分
(一)广义的 Spring:Spring 技术栈
泛指以 Spring Framework 为核心的 Spring 技术栈。
例如:Spring MVC、SpringBoot、Spring Cloud、Spring Data、Spring Security等
(二)狭义的 Spring:Spring Framework
特指:Spring Framework,通常我们将它称为 Spring 框架
Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案。
Spring 有两个最核心模块:IoC 和 AOP
1、IoC
IoC(Inverse of Control :控制反转):指把创建对象过程交给 Spring 进行管理。
AOP(Aspect Oriented Programming:面向切面编程):
- 一种编程范式,用于将横切关注点(如日志、安全等)与业务逻辑分离,从而提高代码的模块化和可维护性。
- AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
1.3 Spring Framework 的特点
- 非侵入式(在使用 Spring 时候不需要依赖其他组件就可以直接使用)
- Spring 对应用程序本身的结构影响非常小,对领域模型可以做到零污染
- 对功能性组件也只需要使用几个简单的注解进行标记,完全不会破坏原有结构
- 控制反转(IoC)
- 翻转资源获取方向,把自己创建资源、向环境索取资源变成环境将资源准备好,我们享受资源注入。
- 面向切面编程(AOP)
- 在不修改源代码的基础上增强代码功能。
- 容器
- Spring IoC 是一个容器,因为它包含并且管理组件对象的生命周期。组件享受到了容器化的管理,替程序员屏蔽了组件创建过程中的大量细节,极大的降低了使用门槛,大幅度提高了开发效率。
- 组件化
- 使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用 XML 和 Java 注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭建超大型复杂应用系统
- 一站式
- 在 IoC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且 Spring 旗下的项目已经涵盖了广泛的领域,很多方面的功能性需求可以在 Spring Framework 的基础上全部使用 Spring 来实现。
1.4 Spring 模块的组成
Spring 6 要求的 JDK 版本是 JDK 17
二、Spring 6 入门
2.1 笔记中涉及到的环境:
- JDK :Java 21
- Maven:3.9.6
- Spring:
基本开发步骤:
父工程
子模块
2.2 构建模块
2.3.1 引入依赖
htttp://spring.io/projects/spring-framework#learn
添加依赖:
<dependencies>
<!--spring context 依赖-->
<!--当你引入 Spring Context依赖后,表示将 Spring 的基础依赖引入了-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.4</version>
</dependency>
<!--junit-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
</dependency>
</dependencies>
2.3.2 程序分析
1、之前创建对象,无参构造执行吗?
无参构造执行
2、不用 new 方式,还可以如何创建对象?——反射
3、创建对象放到哪里?
2.5 启用 Log4j2 日志框架
2.5.1 Log4j2 日志概述
日志很重要。
日志记录了系统行为的时间、地点、状态等相关信息,能够帮助我们了解并监控系统状态,在发生错误或者接近某种危险状态时能够及时提醒我们处理,同时在系统产生问题时,能够帮助我们快速定位、诊断并解决问题。
Apache Log4j2 是一个开源的日志记录组件,使用非常的广泛,在工程中以易用方便代替了 System.out 等打印语句,它是Java 下最流行的日志输入工具
Log4j2 主要由几个重要的组件构成:
2.5.2 引入 Log4j2 依赖
<!--log4j2的依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
2.5.3 加入日志配置文件
在类的根路径下提供 log4j2.xml 配置文件(文件名固定为:log4j2.xml,文件必须放到类根路径下)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<loggers>
<!--
level 指定日志级别,从低到高的优先级:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
trace:追踪,是最低的日志级别,相当于追踪程序的执行
debug:调试,一般在开发中,都将其设置为最低的日志级别
info:信息,输出重要的信息,使用较多
warn:警告,输出警告的信息
error:错误,输出错误信息
fatal:严重错误
-->
<root level="DEBUG">
<appender-ref ref="spring6log"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="log"/>
</root>
</loggers>
<appenders>
<!--输出日志信息到控制台-->
<console name="spring6log" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss sss} [%t] %-3level %logger{1024} - %msg%n"/>
</console>
<!--文件会打印出所有信息,这个 log 每次运行程序会自动清空,由 append 属性决定,适合临时测试用-->
<File name="log" fileName="f:/spring6_log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss sss} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!--这个会打印出所有的信息
每次大小超过 size
则这 size 大小的日志会自动存入按年份-月份建立的文件夹下面进行压缩,
作为存档
-->
<RollingFile name="RollingFile" fileName="f:/spring6_log/app.log" filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="50MB"/>
<!-- DefaultRolloverStrategy 属性若不设置,
则默认为最多同一文件夹下 7 个文件,这里设置了 30-->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</appenders>
</configuration>
2.5.4 测试
2.5.5 使用日志
三、容器:IoC
IoC(Inversion of Control:控制反转):是一种涉及思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。
Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。
- 容器 Bean 对象:使用的是 map 集合;因为map 集合,key-value
- 实例化的方式:
- new
- 使用 工厂
- 使用 反射
IoC 容器是 Spring 框架中的最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。
3.1 IoC 容器
3.1.1 控制反转(IoC)
- 控制反转是一种思想
- 控制反转是为了降低程序耦合度,提高程序扩展力
- 控制反转,反转的是什么?
- 将对象的创建权利交出去,交给第三方容器负责
- 将对象和对象之间关系的维护权交出去,交给第三方容器负责
- 控制反转这种思想如何实现?
- DI(Dependency Injection):依赖注入
IoC 容器中的过程:
3.1.2 依赖注入
依赖注入:实现了控制反转的思想
依赖注入:指 Spring 创建对象的过程中,将对象依赖属性通过配置进行注入。
依赖注入常见的实现方式包括两种:
- 第一种:set 注入
- 第二种:构造注入
package com.atguigu.spring6.iocxml.di;
public class Book {
private String name;
private String author;
//生成构造
//无参构造
public Book() {}
//有参构造
public Book(String name, String author) {
this.name = name;
this.author = author;
}
//生成set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public static void main(String[] args) {
// set 方法注入
Book book = new Book();
book.setName("java");
book.setAuthor("Max");
//通过构造器注入
Book book1 = new Book("c++", "max");
}
}
IoC 是一种控制反转的思想,而 DI 是对 IoC 的一种具体实现。
Bean 管理说的是:Bean 对象的创建,以及 Bean 对象中属性的赋值(或者叫做 Bean 对象之间关系的维护)
3.1.3 IoC 容器在 Spring 的实现
IoC 容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建 IoC 容器。
Spring 提供了 IoC 容器的两种实现方式:
1. BeanFactory
这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给 开发人员使用。
2.ApplicationContext
BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory
3.ApplicationContext 的主要实现类
3.2 基于 XML 管理 bean
3.2.1 搭建子模块 spring6-ioc-xml
1.搭建模块
搭建方式如:spring-first
2.引入配置文件
引入 spring-first 模块配置文件:bean.xml、log4j2.xml
3.添加依赖
<dependencies>
<!--spring context 依赖-->
<!--当你引入 Spring Context依赖后,表示将 Spring 的基础依赖引入了-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.4</version>
</dependency>
<!--junit-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
</dependency>
<!--log4j2的依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
3.2.2 实验一:获取 bean
1.方式一:根据 id 获取
由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象。
2.方式二:根据类型获取
3.方式三:根据 id 和 类型
package com.atguigu.iocxml;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//1.根据 id 获取 bean
User user1 = (User)context.getBean("user");
System.out.println("1 根据id获取bean:" + user1);
//2.根据类型获取bean
User user2 = context.getBean(User.class);
System.out.println("2 根据类型获取bean:" + user2);
//3.根据id和类型获取bean
User user3 = context.getBean("user", User.class);
System.out.println("3 根据类型获取bean:" + user3);
}
}
注意的地方:
当根据类型获取bean时,要求IoC容器中指定类型的bean有且只能有一个
当IoC 容器中一共配置了两个:
<bean id="user" class="com.atguigu.spring6.iocxml.User"></bean>
<bean id="u1" class="com.atguigu.spring6.iocxml.User"></bean>
根据类型获取时会抛出异常:
原因时:
因为bean的class 是com.atguigu.spring6.iocxml.User,这个是它们所共用的。
扩展知识
如果组件类实现了接口,根据结构类型可以获取 bean 吗?
可以,前提是 bean 唯一
如果一个接口有多个实现类,这些实现类都配置了 bean ,根据接口类型可以获取 bean 吗?
不可以,因为 bean 不唯一
结论:
根据类型来获取 bean 时,在满足 bean 唯一性的前提下,其实只是看 :【对象 instanceof 指定的类型】的返回结果,只要返回的是 true 就可以认定为和类型匹配,能够获取到。
Java 中,instanceof 运算符用于判断前面的对象是否是后面的类,或其子类、实现类的实例。如果是返回 true,否则返回 false。也就是说:用 instanceof 关键字做判断时,instanceof 操作符的左右操作必须有继承或实现关系
3.2.3 实验二:依赖注入之 setter 注入
(1)创建 Book 类
Book.java
package com.atguigu.spring6.iocxml.di;
public class Book {
private String name;
private String author;
//生成构造
//无参构造
public Book() {}
//有参构造
public Book(String name, String author) {
this.name = name;
this.author = author;
}
//生成set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
public static void main(String[] args) {
// set 方法注入
Book book = new Book();
book.setName("java");
book.setAuthor("Max");
//通过构造器注入
Book book1 = new Book("c++", "max");
}
}
(2)配置 bean 时为属性赋值
bean-di.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.set 方法注入-->
<bean id="book" class="com.atguigu.spring6.iocxml.di.Book">
<!--属性赋值-->
<property name="name" value="前端开发"></property>
<property name="author" value="max"></property>
</bean>
</beans>
(3)测试
TestBook.java
package com.atguigu.spring6.iocxml.di;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testSetter() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
3.2.4 实验三:依赖注入之构造器注入
(1)创建 Book 类
Book.java
package com.atguigu.spring6.iocxml.di;
public class Book {
private String name;
private String author;
//生成构造
//无参构造
public Book() {
System.out.println("无参数构造执行....");
}
//有参构造
public Book(String name, String author) {
System.out.println("有参数构造执行...");
this.name = name;
this.author = author;
}
//生成set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
public static void main(String[] args) {
// set 方法注入
Book book = new Book();
book.setName("java");
book.setAuthor("Max");
//通过构造器注入
Book book1 = new Book("c++", "max");
}
}
(2)配置 bean 时为属性赋值
bean-di.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 1.set 方法注入-->
<bean id="book" class="com.atguigu.spring6.iocxml.di.Book">
<!--属性赋值-->
<property name="name" value="前端开发"></property>
<property name="author" value="max"></property>
</bean>
<!-- 2. 构造器注入 -->
<bean id="bookConstructor" class="com.atguigu.spring6.iocxml.di.Book">
<constructor-arg name="name" value="Java开发"></constructor-arg>
<constructor-arg name="author" value="Max"></constructor-arg>
</bean>
</beans>
(3)测试
TestBook.java
package com.atguigu.spring6.iocxml.di;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testSetter() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
@Test
public void testConstructor() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("bookConstructor", Book.class);
System.out.println(book);
}
}
3.2.5 实验四:特殊值处理
(1)字面量赋值
就是字面量本身的值
<!-- 使用 value属性给bean的属性赋值时,Spring 会把value属性的值看作字面量-->
<property name="name" value="Java开发"/>
(2)null 值,没有value 值时
<property name="name">
<null />
</property>
(3)xml 实体
(4)CDATA 节
3.2.6 实验五:为对象类型属性赋值
创建部门类:Dept.java
package com.atguigu.spring6.iocxml.ditest;
//部门类
public class Dept {
private String dname;
public void info(){
System.out.println("部门名称:" + dname);
}
}
创建员工类:Emp.java
package com.atguigu.spring6.iocxml.ditest;
//员工类
public class Emp {
//员工属于某个部门
private Dept dept;
private String ename;
private Integer age;
public void work(){
System.out.println(ename + "正在工作" + age);
}
}
方式一、引入外部bean
Dept.java
package com.atguigu.spring6.iocxml.ditest;
//部门类
public class Dept {
private String dname;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public void info(){
System.out.println("部门名称:" + dname);
}
}
Emp.java
package com.atguigu.spring6.iocxml.ditest;
//员工类
public class Emp {
//对象类型属性:员工属于某个部门
private Dept dept;
//员工名称
private String ename;
//员工年龄
private Integer age;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void work(){
System.out.println(ename + "正在工作" + age);
dept.info();
}
}
配置文件 bean-ditest.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
1.创建两个类对象:dept 和 emp
2.在emp的bean标签里面,使用property引入dept的bean
-->
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="美图商家交易开发技术部"/>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--注入对象类型属性
ref 是引入引用的意思,ref的值是: 部门的id
-->
<property name="dept" ref="dept"></property>
<!--普通属性注入-->
<property name="ename" value="刘文涛"></property>
<property name="age" value="18"></property>
</bean>
</beans>
测试类 TestEmp.java
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestEmp {
public static void main(String[] args) {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-ditest.xml");
//员工对象
Emp emp = context.getBean("emp", Emp.class);
emp.work();
}
}
方式二、内部bean
配置文件 bean-ditest.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
1.创建两个类对象:dept 和 emp
2.在emp的bean标签里面,使用property引入dept的bean
-->
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="美图商家交易开发技术部"/>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--注入对象类型属性
ref 是引入引用的意思,ref的值是: 部门的id
-->
<property name="dept" ref="dept"></property>
<!--普通属性注入-->
<property name="ename" value="刘文涛"></property>
<property name="age" value="18"></property>
</bean>
<!--内部bean 注入-->
<bean id="emp2" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="ename" value="Max"></property>
<property name="age" value="25"></property>
<!--内部bean-->
<property name="dept">
<bean id="dept2" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
</beans>
测试类 TestEmp.java
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestEmp {
public static void main(String[] args) {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-ditest.xml");
//员工对象
Emp emp2 = context.getBean("emp2", Emp.class);
emp2.work();
}
}
方式三、级联属性赋值
配置文件 bean-ditest.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
1.创建两个类对象:dept 和 emp
2.在emp的bean标签里面,使用property引入dept的bean
-->
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="美图商家交易开发技术部"/>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--注入对象类型属性
ref 是引入引用的意思,ref的值是: 部门的id
-->
<property name="dept" ref="dept"></property>
<!--普通属性注入-->
<property name="ename" value="刘文涛"></property>
<property name="age" value="18"></property>
</bean>
<!--内部bean 注入-->
<bean id="emp2" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="ename" value="Max"></property>
<property name="age" value="25"></property>
<!--内部bean-->
<property name="dept">
<bean id="dept2" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
<!--第三种:级联注入-->
<bean id="dept3" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="财务部"></property>
</bean>
<bean id="emp3" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="ename" value="Alice"></property>
<property name="age" value="20"></property>
<property name="dept" ref="dept3"></property>
<property name="dept.dname" value="食堂"></property>
</bean>
</beans>
测试类 TestEmp.java
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestEmp {
public static void main(String[] args) {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-ditest.xml");
//员工对象
Emp emp3 = context.getBean("emp3", Emp.class);
emp3.work();
}
}
3.2.7 实验六:为数组类型属性赋值
配置文件 bean-diarray.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="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--普通属性-->
<property name="ename" value="Lucy"></property>
<property name="age" value="20"></property>
<!--对象类型属性-->
<property name="dept" ref="dept"></property>
<!--数组类型属性-->
<property name="hobbys">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>敲代码</value>
</array>
</property>
</bean>
</beans>
3.2.8 实验七:为集合类型属性赋值
(1)为List集合类型属性赋值
配置文件 bean-dilist.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="empOne" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="ename" value="Lucy"></property>
<property name="age" value="18"></property>
</bean>
<bean id="empTwo" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="ename" value="Mary"></property>
<property name="age" value="30"></property>
</bean>
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
<property name="empList">
<list>
<ref bean="empOne"></ref>
<ref bean="empTwo"></ref>
</list>
</property>
</bean>
</beans>
TestDept.java
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDept {
public static void main(String[] args) {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-dilist.xml");
Dept dept = context.getBean("dept", Dept.class);
dept.info();
}
}
(2)为Map集合类型属性赋值
Student.java
package com.atguigu.spring6.iocxml.dimap;
import java.util.Map;
public class Student {
//一个学生对应多个老师
private Map<String,Teacher> teacherMap;
private String sid;
private String sname;
public void run(){
System.out.println("学生编号:"+sid+"学生姓名:"+sname);
System.out.println(teacherMap);
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
Teacher.java
package com.atguigu.spring6.iocxml.dimap;
public class Teacher {
private String teacherId;
private String teacherName;
public String getTeacherId() {
return teacherId;
}
public void setTeacherId(String teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
@Override
public String toString() {
return "Teacher{" +
"teacherId='" + teacherId + '\'' +
", teacherName='" + teacherName + '\'' +
'}';
}
}
bean-dimap.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">
<!--
1.创建两个对象
2.注入普通类型属性
3.在学生bean注入map集合类型
-->
<bean id="teacherOne" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="0001"></property>
<property name="teacherName" value="苍老师"></property>
</bean>
<bean id="teacherTwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="0002"></property>
<property name="teacherName" value="上官老师"></property>
</bean>
<bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
<property name="sid" value="180001"></property>
<property name="sname" value="Max"></property>
<!--在学生bean注入map集合类型属性-->
<property name="teacherMap">
<map>
<entry>
<key>
<value>10010 </value>
</key>
<ref bean="teacherOne"></ref>
</entry>
<entry>
<key>
<value>10086</value>
</key>
<ref bean="teacherTwo"></ref>
</entry>
</map>
</property>
</bean>
</beans>
TestStu.java
package com.atguigu.spring6.iocxml.dimap;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStu {
@Test
public void test(){
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-dimap.xml");
Student student = context.getBean("student", Student.class);
student.run();
}
}
(3)引用集合类型的bean
Student.java
package com.atguigu.spring6.iocxml.dimap;
import java.util.List;
import java.util.Map;
public class Student {
//一个学生可以上多节课
private List<Lesson> lessonList;
//一个学生对应多个老师
private Map<String,Teacher> teacherMap;
private String sid;
private String sname;
public void run(){
System.out.println("学生编号:"+sid+"学生姓名:"+sname);
System.out.println(teacherMap);
System.out.println(lessonList);
}
public List<Lesson> getLessonList() {
return lessonList;
}
public void setLessonList(List<Lesson> lessonList) {
this.lessonList = lessonList;
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
Lesson.java
package com.atguigu.spring6.iocxml.dimap;
public class Lesson {
private String lessonName;
public String getLessonName() {
return lessonName;
}
public void setLessonName(String lessonName) {
this.lessonName = lessonName;
}
@Override
public String toString() {
return "Lesson{" +
"lessonName='" + lessonName + '\'' +
'}';
}
}
Teacher.java
package com.atguigu.spring6.iocxml.dimap;
public class Teacher {
private String teacherId;
private String teacherName;
public String getTeacherId() {
return teacherId;
}
public void setTeacherId(String teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
@Override
public String toString() {
return "Teacher{" +
"teacherId='" + teacherId + '\'' +
", teacherName='" + teacherName + '\'' +
'}';
}
}
TestStu.java
package com.atguigu.spring6.iocxml.dimap;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStu {
@Test
public void test(){
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diref.xml");
Student student = context.getBean("student", Student.class);
student.run();
}
}
配置文件bean-diref.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
1.创建三个对象
2.注入普通类型属性
3.使用 util:类型 定义
4.在学生bean引入util:类型定义bean,完成list、map类型属性注入
-->
<bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
<property name="sid" value="1001"></property>
<property name="sname" value="Max"></property>
<!--注入list、map类型属性-->
<property name="lessonList" ref="lessonList"></property>
<property name="teacherMap" ref="teacherMap"></property>
</bean>
<util:list id="lessonList">
<ref bean="lessonOne"></ref>
<ref bean="lessonTwo"></ref>
</util:list>
<util:map id="teacherMap">
<entry>
<key>
<value>1</value>
</key>
<ref bean="teacherOne"></ref>
</entry>
<entry>
<key>
<value>2</value>
</key>
<ref bean="teacherTwo"></ref>
</entry>
</util:map>
<bean id="teacherOne" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="2001"></property>
<property name="teacherName" value="苍老师"></property>
</bean>
<bean id="teacherTwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="2002"></property>
<property name="teacherName" value="玛丽莲老师"></property>
</bean>
<bean id="lessonOne" class="com.atguigu.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="Java开发"></property>
</bean>
<bean id="lessonTwo" class="com.atguigu.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="前端开发"></property>
</bean>
</beans>
3.2.9 实验八:p 命名空间
3.2.10 实验九:引入外部属性文件
<!--MySQL 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!--数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
bean-jdbc.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: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>
TestJdbc.java
package com.atguigu.spring6.iocxml.jdbc;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestJdbc {
@Test
public void demo2(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-jdbc.xml");
DruidDataSource dataSource = context.getBean(DruidDataSource.class);
System.out.println(dataSource.getUrl());
}
@Test
public void demo1(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/spring?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
}
}
3.2.11 实验十:bean 的作用域
单实例 singleton
多实例 prototype
3.2.12 实验十一:bean 的生命周期
User.java
package com.atguigu.spring6.iocxml.life;
public class User {
//无参数构造
public User(){
System.out.println("1.bean对象创建,调用无参构造器方法");
}
public void setName(String name) {
System.out.println("2.给bean对象设置属性值");
this.name = name;
}
//初始化的方法
public void initMethod(){
System.out.println("4.bean对象初始化,调用指定的初始化方法");
}
//销毁的方法
public void destroyMethod(){
System.out.println("7.bean对象销毁,调用指定的销毁方法");
}
private String name;
public String getName() {
return name;
}
}
bean-life.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.atguigu.spring6.iocxml.life.User" scope="singleton" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="Lucy"></property>
</bean>
</beans>
TestUser.java
package com.atguigu.spring6.iocxml.life;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
//加载配置文件
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean-life.xml");
User user = context.getBean("user", User.class);
System.out.println("6.bean对象创建完成了,可以使用");
System.out.println(user);
context.close();//销毁方法
}
}
bean后置处理器
myBeanPost.java
package com.atguigu.spring6.iocxml.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("3.bean后置处理器,初始化之前执行");
System.out.println(beanName + "::" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("5.bean后置处理器,初始化之后执行");
System.out.println(beanName + "::" + bean);
return bean;
}
}
bean-life.xml
<!--bean的后置处理器要放入IoC容器中才能生效-->
<bean id="myBeanPost" class="com.atguigu.spring6.iocxml.life.MyBeanPost"></bean>
3.2.13 实验十二:FactoryBean
User.java
package com.atguigu.spring6.iocxml.factorybean;
public class User {
}
MyFactoryBean.java
package com.atguigu.spring6.iocxml.factorybean;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
bean-factorybean.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.atguigu.spring6.iocxml.factorybean.MyFactoryBean"></bean>
</beans>
TestUser.java
package com.atguigu.spring6.iocxml.factorybean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
//加载配置文件,获取IoC容器
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-factorybean.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
}
3.2.14 实验十三:基于 xml 自动装配
在controller注入service,在service注入dao
根据byName 要保证属性名和类型一致(name和type)
UserController.java
package com.atguigu.spring6.iocxml.auto.controller;
import com.atguigu.spring6.iocxml.auto.service.UserService;
import com.atguigu.spring6.iocxml.auto.service.UserServiceImpl;
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser(){
System.out.println("controller 方法执行了...");
//调用service的方法
userService.addUserService();
// UserService userService = new UserServiceImpl();
// userService.addUserService();
}
}
UserService.java
package com.atguigu.spring6.iocxml.auto.service;
public interface UserService {
public void addUserService();
}
UserServiceImpl.java
package com.atguigu.spring6.iocxml.auto.service;
import com.atguigu.spring6.iocxml.auto.dao.UserDao;
import com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUserService() {
System.out.println("userService方法执行了....");
//调用dao的方法
userDao.addUserDao();
// UserDao userDao = new UserDaoImpl();
// userDao.addUserDao();
}
}
UserDao.java
package com.atguigu.spring6.iocxml.auto.dao;
public interface UserDao {
public void addUserDao();
}
UserDaoImpl.java
package com.atguigu.spring6.iocxml.auto.dao;
public class UserDaoImpl implements UserDao{
@Override
public void addUserDao() {
System.out.println("userDao 方法执行了...");
}
}
bean-auto.xml
<!--自动装配:根据类型进行注入-->
<bean id="userController" class="com.atguigu.spring6.iocxml.auto.controller.UserController" autowire="byType"></bean>
<bean id="userServiceImpl" class="com.atguigu.spring6.iocxml.auto.service.UserServiceImpl" autowire="byType"></bean>
<bean id="userDaoImpl" class="com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl"></bean>
3.3 基于注解管理 bean(⭐)
3.3.1 搭建子模块spring6-ioc-annotation
3.3.2 开启组件扫描
3.3.3 使用注解定义 Bean
使用注解创建对象
3.3.4 实验一:@Autowired注入
(1)场景一:属性注入
(2)场景二:set注入
(3)场景三:构造方法注入
(4)场景四:形参注入
(5)场景五:只有一个有参数构造函数,无注解
(6)场景六:@Autowired注解和@Qualifier注解联合
当一个接口有多个实现类时
3.3.5 实验二:@Resource注入
(1)场景一:根据name注入
(2)场景二:name未知注入
根据属性名字找到对应关系注入
(3)场景三:其他情况
3.3.6 Spring 全注解开发 - 用配置类来代替配置文件