【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化身

相关推荐
李小星同志11 分钟前
高级算法设计与分析 学习笔记6 B树
笔记·学习
哈喽,树先生16 分钟前
1.Seata 1.5.2 seata-server搭建
spring·springcloud
霜晨月c23 分钟前
MFC 使用细节
笔记·学习·mfc
Jhxbdks35 分钟前
C语言中的一些小知识(二)
c语言·开发语言·笔记
AlexMercer10121 小时前
【C++】二、数据类型 (同C)
c语言·开发语言·数据结构·c++·笔记·算法
微刻时光1 小时前
Redis集群知识及实战
数据库·redis·笔记·学习·程序人生·缓存
chnyi6_ya2 小时前
一些写leetcode的笔记
笔记·leetcode·c#
青椒大仙KI113 小时前
24/9/19 算法笔记 kaggle BankChurn数据分类
笔记·算法·分类
小菜yh3 小时前
关于Redis
java·数据库·spring boot·redis·spring·缓存