根据 【动力节点】最新Spring框架教程,全网首套Spring6教程,跟老杜从零学spring入门到高级 以及老杜的原版笔记 https://www.yuque.com/docs/share/866abad4-7106-45e7-afcd-245a733b073f?# 《Spring6》 进行整理, 文档密码:mg9b
Spring 相关文章整理汇总归纳于:https://www.yuque.com/u27599042/zuisie
Spring 入门程序
创建项目
- 这里采用在工程 project 中创建模块 model 的形式
设置项目采用的编码
设置项目的Maven
设置项目使用的JDK
创建第一个 Spring 模块
引入依赖
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cw.spring.study</groupId>
<artifactId>spring-study-001</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 导包方式为 jar -->
<packaging>jar</packaging>
<properties>
<!-- JDK 使用 17 -->
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<!-- 引入项目所需要的依赖 -->
<dependencies>
<!-- spring 基础依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.8</version>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 刷新,让Maven加载依赖
定义普通 Java 类
- 在开发中,普通Java对象,称为 pojo(Plain Old Java Object),或者称为 java bean(咖啡豆),也叫 domain(领域模型)
java
/**
* ClassName: User
* Package: cw.spring.study.pojo
* Description:
*
* @Author tcw
* @Create 2023-05-25 17:20
* @Version 1.0
*/
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
编写 Spring 配置文件
- Spring 配置文件放在类根路径下,即 resource 目录下
- 该文件放在类的根路径下方便后期的移植
- 放在resources目录下,相当于放在类的根路径下
- Spring的配置文件的命名任意
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">
<!-- spring的配置文件 -->
<!-- 在配置文件中配置bean,spring才能帮助我们管理这个对象 -->
<!--
id: bean的唯一标识,对象的唯一标识
class: 类的全路径,用来指定要创建的java对象的类名
-->
<bean id="userBean" class="cw.spring.study.pojo.User" />
</beans>
类根路径
- 不管是 maven 还是普通的 java 模块,只要是 idea 文件夹中变成蓝色的部分,就是可以理解为类路径的起始地点,之后的编译就是由蓝色文件夹开始算类路径,自定义文件夹后用 idea 标记为 resource 后的文件夹也会被最终打包到类路径下
- 图中的蓝色Java目录和resource目录都相当于类的根路径,就是打包后,包的根路径
- 由于test目录中的文件主要是测试程序,测试程序一般不会被打包到JAR包,test目录下的子目录和文件会被单独打包到另外的文件夹下
编写测试类
java
public class Test {
@org.junit.Test
public void tset1() {
// 第一步:获取Spring容器对象。
// ApplicationContext 翻译为:应用上下文。其实就是Spring容器。
// ApplicationContext 是一个接口。
// ApplicationContext 接口下有很多实现类。其中有一个实现类叫做:ClassPathXmlApplicationContext
// ClassPathXmlApplicationContext 专门用于从类路径当中加载spring配置文件的一个Spring上下文对象。
// 这行代码只要执行,就相当于启动了Spring容器,同时会解析spring.xml(Spring配置文件名)文件,
// 并且实例化在Spring配置文件中配置的所有的bean对象,创建完成对象后会将其放到spring容器当中。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
// 第二步:根据bean的id从Spring容器中获取这个对象。(id Bean的唯一标识)
Object userBean = applicationContext.getBean("userBean");
System.out.println(userBean);
}
}
Spring 入门程序分析
- 在spring的配置文件中,每个bean的id是不能重名,因为id是每个bean的唯一表示,用于通过容器对象获取相应的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="userBean" class="cw.spring.study.pojo.User" />
<bean id="userBean" class="cw.spring.study.pojo.User" />
</beans>
org.springframework.beans.factory.parsing.BeanDefinitionParsingException:
Configuration problem: Bean name 'userBean' is already used in this <beans> element
Offending resource: class path resource [spring.xml]
- spring是通过反射机制调用类的无参数构造方法来创建对象的,所以要想让spring给你创建对象,必须保证无参数构造方法是存在的。
java
public class User {
private String name;
private Integer age;
public User() {
System.out.println("User 无参构造方法执行...");
}
...
}
- spring把创建好的对象存储到一个Map集合当中
- bean对象最终存储在spring容器中,在spring源码底层就是一个map集合,存储bean的map在DefaultListableBeanFactory类中
- Spring容器加载到Bean类时 , 会把这个类的描述信息, 以包名加类名的方式存到beanDefinitionMap 中,
Map<String,BeanDefinition> , 其中- String是Key , 默认是类名首字母小写,bean的id
- BeanDefinition , 存的是类的定义(描述信息) , 我们通常叫BeanDefinition接口为 : bean的定义对象。
java
public class DefaultListableBeanFactory
extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
...
private final Map<String, BeanDefinition> beanDefinitionMap;
...
}
- spring配置文件名字是我们负责提供的,spring配置文件的名字是随意的
- 因为在Spring程序中获取Spring配置文件创建Spring容器中,Spring配置文件是由我们进行指定的,所以spring配置文件的名字可以是任意的
- spring的配置文件可以有多个,在ClassPathXmlApplicationContext构造方法的参数上传递文件路径即可。且配置文件的文件名、文件路径都是任意的
java
//ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
//ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml", "beans.xml");
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml", "beans.xml", "xml/beans.xml");
// 源码:
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, (ApplicationContext)null);
}
- 在spring配置文件中配置的bean可以是任意类,只要这个类不是抽象的,并且提供了无参数构造方法。
- getBean()方法调用时,id不存在的时候,会出现异常
java
@org.junit.Test
public void tset1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Object userBean = applicationContext.getBean("userBean123");
System.out.println(userBean);
}
- getBean()方法返回的类型是Object,如果访问子类的特有属性和方法时,还需要向下转型,有其它办法可以解决这个问题吗?
java
//Object nowTime = applicationContext.getBean("nowTime");
//Date nowTime = (Date) applicationContext.getBean("nowTime");
// 不想强制类型转换,可以使用以下代码(通过第二个参数来指定返回的bean的类型。)
Date nowTime = applicationContext.getBean("nowTime", Date.class);
- ClassPathXmlApplicationContext是从类路径中加载配置文件,如果没有在类路径当中,又应该如何加载配置文件呢?
- 没有在类路径中的话,需要使用FileSystemXmlApplicationContext类进行加载配置文件。
- 从指定的文件路径加载配置文件
- 这种方式较少用。一般都是将配置文件放到类路径当中,这样可移植性更强。
- 没有在类路径中的话,需要使用FileSystemXmlApplicationContext类进行加载配置文件。
java
ApplicationContext applicationContext2 = new FileSystemXmlApplicationContext("d:/spring6.xml");
- ApplicationContext的超级父接口BeanFactory。
- BeanFactory是Spring容器的超级接口。
- ApplicationContext是BeanFactory的子接口。
java
//ApplicationContext接口的超级父接口是:BeanFactory
//BeanFactory翻译为Bean工厂,就是能够生产Bean对象的一个工厂对象
//BeanFactory是IoC容器的顶级接口。
//Spring的IoC容器底层实际上使用了:工厂模式。
//Spring底层的IoC是怎么实现的?XML解析 + 工厂模式 + 反射机制
//ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
BeanFactory beanFactory = new ClassPathXmlApplicationContext("spring6.xml");
User user = applicationContext.getBean("userBean", User.class);
System.out.println(user);
- Spring底层的IoC容器是通过:XML解析+工厂模式+反射机制实现的。
- spring不是在调用getBean()方法的时候创建对象,执行
new ClassPathXmlApplicationContext("spring6.xml");
加载配置文件的时候,就会实例化对象。
java
@org.junit.Test
public void tset1() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
}