【Spring】Sping笔记01

参考学习:b站浪飞yes


# 一、Spring 引入

**事务实现**

```java

public class EmployeeServiceImpl implements IEmployeeService {

public void save(Employee employee){

// 打开资源

// 开启事务

try {

// 保存业务操作

// 提交事务

}catch (Exception e){

// 回滚事务

}finally{

// 释放资源

}

}

// ...

}

```

**MyBatis框架**

```java

public void update(Employee emp){

SqlSession session = MyBatisUtil.getSession();

EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);

employeeMapper.update(emp);

session.commit();

session.close();

}

```

**请求接口**

```java

@WebServlet("/list")

public class EmployeeServlet extends HttpServlet {

@Override

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.setContentType("application/json;charset=utf-8");

// 获得字符打印流对象

PrintWriter out = resp.getWriter();

// 响应数据给浏览器显示

String json = "{\"message\":\"success\", \"data\":[{\"id\":1,\"name\":\"dafei\", \"age\":18},{\"id\":2,\"name\":\"xiaoye\", \"age\":16}]}";

out.print(json);

}

}

```

如果说下面代码等价上面的,有啥感想?

**事务实现**

```java

public class EmployeeServiceImpl implements IEmployeeService {

@Transactional

public void save(Employee employee){

}

// ...

}

```

**MyBatis框架**

```java

@Autowired

private EmployeeMapper employeeMapper;

public void update(Employee emp){

employeeMapper.update(emp);

}

```

**请求接口**

```java

@RequestMapping("/list")

public class EmployeeController {

@ResponseBody

protected R service() {

return new R.ok(Arrays.asList(new Employee(1L, "dafei",18), new Employee(2L,"xiaoye", 16)));

}

}

```

请使用:**Spring框架**

# 二、Spring 介绍

## 2.1 简介

官网:https://spring.io/projects/spring-framework#learn

Spring 是一个轻量级的 **IoC / DI和 AOP 容器**的开源框架,致力于构建轻量级的 JavaEE 应用,**简化应用开发**,本身涵盖了传统应用开发,还拓展到移动端,大数据等领域。

什么是容器(Container):从程序设计角度看就是**装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期**。

**大白话:Spring是一个可以存放对象的容器,并管理这些对象的生老病死,我们可以通过Spring API随意操作这些对象。**

## 2.2 Spring 优势

Spring 不能帮我们写业务逻辑,但是可以能帮助我们简化开发,作用如下

  • Spring 能帮我们低侵入/低耦合地根据配置文件创建及组装对象之间的依赖关系。

  • Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制等。

  • Spring 能非常简单的且强大的声明式事务管理。

  • Spring 提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,且自己也提供了一套 JDBC 模板来方便数据库访问。

  • Spring 提供与第三方 Web(如 MyBatis)框架无缝集成,且自己也提供了一套 Spring MVC 框架,来方便 Web 层搭建。

  • Spring 能方便的与如 Java Mail、任务调度、缓存框架等技术整合,降低开发难度。

**一句话:牛逼**

## 2.3 Spring 架构体系

![Spring FrameWork 体系]

  • Core Container(核心容器 IoC)包含有 Beans、Core、Context 和 SpEL 模块。

  • Test 模块支持使用 JUnit 和 TestNG 对 Spring 组件进行测试。

  • AOP 模块提供了一个符合 AOP 联盟标准的面向切面编程的实现。

  • Data Access / Integration 层包含有 JDBC、ORM、OXM、JMS 和 Transaction 模块。

  • Web 层包含了 Web、Web-Servlet、WebSocket、Web-Porlet 模块。

课程重点设涉及 **Test、Core Container、AOP、TX、MVC。**

2.4 Spring 版本

```java

snapshot:是工程版本上的概念,表示快照版本,也就是相对稳定版本,但是会再进行改进,最好不要用于生产环境

Alpha:内测版,BUG多,开发人员开发过程中使用,希腊字母α,第一,指最初版

Beta:早期版本,有缺陷,没有严重BUG,可能加入新功能,进一步开发完善

Gamma: 经Beta 版,完善修改,成为正式发布的候选版本(Release Candidate)

RC:(Release Candidate):候选版本,几乎就是正式版了

GA:(Ggeneral Availability):发行稳定版,官方推荐使用此版本

R,RELEASE:正式版,等价于GA

```

**JDK版本要求**:

| Spring Framework版本 | JDK版本 |

| -------------------- | --------- |

| 6.0.x | JDK 17-21 |

| 5.3.x | JDK 8-19 |

| 5.2.x | JDK 8-15 |

| 5.1.x | JDK 8-12 |

| 5.0.x | JDK 8-10 |

| 4.3.x | JDK 6-8 |

https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions

**Spring 6.x之后JDK版本要求是JDK17,而当前我们使用JDK11,所以选择5.3.x版本,新版本控的同学自己选择。**

此处选择Spring版本:**Spring-5.3.34**

# 三、Spring 入门案例

**需求:使用spring容器管理对象**

**步骤1:创建标准maven项目:spring_ioc_di_aop**

**步骤2:导入Spring依赖**

```xml

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.3.34</version>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>1.18.26</version>

</dependency>

<dependency>

<groupId>org.junit.jupiter</groupId>

<artifactId>junit-jupiter-engine</artifactId>

<version>5.8.1</version>

<scope>test</scope>

</dependency>

</dependencies>

```

**步骤3:创建普通domain对象**

```java

package cn.wolfcode.spring._01_hello;

import lombok.Getter;

import lombok.Setter;

import lombok.ToString;

@Setter

@Getter

public class User {

private String username;

private String password;

}

```

**步骤4:创建Spring容器文件:01.hello.xml**

```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="cn.wolfcode.spring._01_hello.User"></bean>

</beans>

```

**步骤5:测试Spring容器**

添加junit5测试依赖

```xml

<dependency>

<groupId>org.junit.jupiter</groupId>

<artifactId>junit-jupiter</artifactId>

<version>5.8.2</version>

<scope>test</scope>

</dependency>

```

**HelloTest测试类**

```java

package cn.wolfcode.spring.test._01_hello;

import cn.wolfcode.spring._01_hello.User;

import org.junit.jupiter.api.Test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloTest {

@Test

public void testHello(){

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:01.hello.xml");

User user = context.getBean("user", User.class);

System.out.println(user);

System.out.println(user.getUsername());

System.out.println(user.getPassword());

}

}

```

# 四、Spring 入门解析

## 4.1 hello.xml

在hello.xml文件中最核心的代码

```xml

<bean id="user" class="cn.wolfcode.spring._01_hello.User">

<property name="username" value="dafei"></property>

<property name="password" value="666"></property>

</bean>

```

xml文件+上面代码,Spring做了一下操作:

  • 借助xml文件创建了Spring容器

  • 解析class指定的全限定类名,并通过反射创建了User对象,并初始化属性

  • 将创建User对象缓存在spring容器中

  • 建立起 user<---->User对象的映射,后续可以通过id获取User对象

## 4.2 HelloTest.java

### 4.2.1 ClassPathXmlApplicationContext

HelloTest测试案例里面有2行核心代码

```java

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:01.hello.xml");

```

  • **ClassPathXmlApplicationContext**:Spring框架的上下文对象,一般可以理解为Spring容器的化身之一,操作它的API,等价于操作Spring容器。

  • 框架启动时,ClassPathXmlApplicationContext 会从classpath加载配置文件,并初始化 Spring 容器,并根据配置文件中的信息创建和管理相应的 Bean 实例(比如案例中User对象,Spring容器对象称之为Bean)。

  • 通过 ClassPathXmlApplicationContext 提供的API可以操作容器中的Bean实例。

**Spring容器各种化身体系(继承)**

**BeanFactory**:

  • **功能**:是 Spring 框架最基本的 IoC 容器,提供了最基本的 IoC 功能,包括依赖注入和 Bean 的生命周期管理。

  • **特点**:BeanFactory 是 Spring IoC 容器的最底层接口,提供了延迟加载 Bean 的特性,当获取 Bean 时才进行实例化和初始化。

  • **使用场景**:适用于资源受限或需要手动控制 Bean 实例化的场景,如移动设备或性能要求较高的环境。

**ApplicationContext**:

  • **功能**:是 BeanFactory 接口的扩展,提供了更多高级特性,如国际化支持、事件传播、AOP 集成等,是 Spring 中最常用的 IoC 容器接口。

  • **特点**:ApplicationContext 在 BeanFactory 的基础上增加了更多的功能和便利性,例如自动注册 BeanPostProcessor、Bean 生命周期管理、资源加载、消息源等。

  • **使用场景**:几乎所有 Spring 应用都应该使用 ApplicationContext,除非有特殊需求需要直接使用 BeanFactory。

**AnnotationConfigApplicationContext**:

  • **功能**:用于基于注解配置的 Spring 应用上下文。通过 Java 配置类(使用注解如 @Configuration、@ComponentScan、@Bean 等)来定义和管理 Spring Bean。

  • **使用场景**:适用于完全基于注解配置的 Spring 应用,不依赖 XML 配置文件。

**ClassPathXmlApplicationContext**:

  • **功能**:用于基于 XML 配置的 Spring 应用上下文。从类路径下加载指定的 XML 配置文件,并初始化 Spring 容器和 Bean。

  • **使用场景**:适用于传统的基于 XML 配置的 Spring 应用,配置信息存储在 XML 文件中。

**总结:开发涉及到操作Spring 容器,一般使用ApplicationContext即可**

**注意:上面类虽说可以认为是Spring容器化身,但它们都是独立对象。不能直接画等号。**

### 4.2.2 getBean

getBean:从Spring容器中获取Bean对象,常规用法:

```java

//通过name/id获取Bean对象

User user = (User) context.getBean("user");

//通过对象类型获取Bean对象,如果容器中存在多个相同User实例会报错

User user = context.getBean(User.class);

//通过name/id + 类型获取Bean对象,如果容器中存在多个相同User,但是name/id不一样,不报错

User user = context.getBean("user", User.class);

```

## 4.3 常见异常

**异常1:NoSuchBeanDefinitionException: No bean named 'user2' available**

按照 bean 名称去获取 bean 时,不存在名称为 user2的 bean。

**异常2:NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.wolfcode._01_hello.User' available: expected single matching bean but found 2: User,User2**

按照 cn.wolfcode._01_hello.User类型去获取 bean 时,期望找到该类型唯一的一个 bean,可是此时找到了两个。

**异常3:BeanDefinitionParsingException: Configuration problem: Bean name 'User' is already used in this <beans> element Offending resource: class path resource [01.hello.xml]**

# 五、Spring 测试

Spring 测试有2种场景

## 5.1 场景1:Junit5

每个测试都要重新启动 Spring 容器,启动容器的开销大,测试效率低下。不应该是测试代码管理 Spring 容器,应该是 Spring 容器来管理测试代码。

一般不用

## 5.2 场景2:Spring提供测试

**优势**:

  • 只需启动一个容器,并管理测试代码

  • 减少很多代码的书写

![使用 Spring 测试]

操作过程

  • 添加测试依赖

```xml

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>5.3.34</version>

<scope>test</scope>

</dependency>

```

  • 代码测试

```java

//在测试方法之前启动容器

//@RunWith(SpringJUnit4ClassRunner.class) //junit4

@ExtendWith(SpringExtension.class) //junit5

@ContextConfiguration("classpath:01.hello.xml") // 指定加载的配置文件

public class HelloSpringTest {

@Autowired // @Autowired 后面讲注解使用再说,此处表示从容器中获取ctx对象

private ApplicationContext ctx; //spring容器

@Test

public void testHello(){

User user = ctx.getBean("user", User.class);

System.out.println(user);

}

}

```

这里注意,

  • 使用junit4 跟 junit5有区别

  • 导入Spring 容器,直接使用ApplicationContext化身

相关推荐
QT 小鲜肉1 小时前
【Linux命令大全】001.文件管理之git命令(实操篇)
linux·服务器·笔记·git·elasticsearch
半夏知半秋1 小时前
docker常用指令整理
运维·笔记·后端·学习·docker·容器
LXS_3572 小时前
Day 18 C++提高 之 STL常用容器(string、vector、deque)
开发语言·c++·笔记·学习方法·改行学it
蒸蒸yyyyzwd2 小时前
网络编程——threadpool.h学习笔记
笔记·学习
浪子不回头4152 小时前
SGLang学习笔记
人工智能·笔记·学习
廋到被风吹走2 小时前
【Spring】DispatcherServlet解析
java·后端·spring
廋到被风吹走2 小时前
【Spring】PlatformTransactionManager详解
java·spring·wpf
Cricyta Sevina3 小时前
Java IO 基础理论知识笔记
java·开发语言·笔记
それども4 小时前
Spring Bean 的name可以相同吗
java·后端·spring
EchoL、5 小时前
Obsidian使用学习
笔记·学习