常用注解

SpringBoot

@SpringBootApplication

1
// 启动类上面加

@Configuration

1
// config 包下的类都是配置类,这些类上面要加 @Configuration

@Value(待完善)

1
// @Value 用于注入外部属性值到 Spring 管理的 Bean 中。它可以读取配置文件(如.properties或.yml)、环境变量、系统属性,或直接指定默认值。

SpringMVC

@RestController(待完善)

1
// 相当于 Restful + Controller

@Controller

1
// 在 controller 包下,一般用 RestController

@RestControllerAdvice

1
2
// 用于统一异常处理业务中的类名上
// 相当于 @ResponseBody + @ControllerAdvice

@ControllerAdvice

1
// 用于统一异常处理业务中的类名上

@RequestMapping

1
// 建立公共的请求路径 @RequestMapping("/depts")

@ResponseBody

1
// 若类用 @Controller 标注,需在方法上显式添加 @ResponseBody。

@RequestParm

1
// 设置默认参数

@RequestBody & @Pathvariable

特性 @PathVariable @RequestBody
数据来源 URL路径部分 请求体
常用场景 GET/DELETE请求获取资源 POST/PUT请求提交数据
数据格式 简单类型(String, Long等) 复杂对象(JSON/XML等)
1
2
3
4
5
6
7
8
9
10
11
12
// 把前端传递的json数据填充到实体类中
@RequestBody
public Result save(@RequestBody Emp emp)


@DeleteMapping("/{user_id}")
public Result delete(@PathVariable Integer user_id){
log.info("根据user_id删除用户:{}",user_id);
//调用service删除用户
UserService.delete(user_id);
return Result.success();
}

Spring

基本注解(增加可读性)

注解 用途 适用场景
@Component 通用组件 普通 Bean
@Service 业务逻辑层 Service 类
@Repository 数据访问层 DAO/Repository 类
@Controller Web 控制器 MVC 的 Controller

@Autowried

1
// 自动注入

@Bean

1
// 声明是一个 Bean 对象,告诉Spring:“此方法的返回值应注册为应用上下文中的一个Bean”,目前只在配置包下使用,方法名默认作为Bean的名称(可指定)

@Aspect

1
// 切面类,在AOP,如统计方法耗时的方法上使用

Spring

IOC

什么是 IOC

​ Spring的IOC,也就是控制反转,它的核心思想是让对象的创建和依赖关系由容器来控制,不是我们自己new出来的,这样各个组件之间就能保持松散的耦合。

​ 这里的容器实际上就是个Map, Map 中存放的是各种对象。Spring容器可以在运行时动态地将依赖注入到需要它们的对象中,而不是对象自己去寻找或创建依赖。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。举例来说,在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了。

如何配置

​ 使用配置可以告诉Spring容器如何创建对象、如何管理对象的生命周期。Spring 时代我们一般通过 XML 文件来配置,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

​ 总结来说,Spring的IOC容器是一个中央化的、负责管理应用中所有对象生命周期的强大工具

DI

IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的.

​ DI**(依赖注入)其实就是IOC的另外一种说法,DI是由Martin Fowler 在2004年初的一篇论文中首次提出的。他总结:控制的什么被反转了?就是:获得依赖对象的方式反转了。**

AOP

面向切面编程(Aspect Oriented Programming),或者面向方法编程。

​ 面向切面编程,可以说是面向对象编程的补充和完善。OOP(Object Oriented Programming) 引入封装、继承、多态等概念来建立一种对象层次结构。OOP允许开发者定义纵向的关系,但并不适合定义横向的 关系,例如日志功能。AOP 技术恰恰相反,它利用一种称为”横切”的技术,剖解开封装的对象内部,将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为切面,降低模块之间的耦合度,有利于未来的操作和维护。

SpringAOP代理由 Spring 的IOC容器负责生成、管理,其依赖关系也由 IOC 容器负责管理。因此, AOP 代理可以直接使用容器中的其它 bean 实例作为目标。Spring 创建代理的规则为:

  1. 默认使用 JDK 动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
  2. 当需要代理类,而不是代理接口的时候,Spring 会切换为使用 CGLIB代理 ,也可强制使用 CGLIB

纵观 AOP 编程,程序员只需要参与三个部分:

  1. 定义普通业务组件
  2. 定义切入点,一个切入点可能横切多个业务组件
  3. 定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作

​ 所以进行 AOP 编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP 框架将自动生成 AOP 代理,即: 代理对象的方法=增强处理+被代理对象的方法。

切入点代码

@Pointcut(“execution(* com.iweb.spring..(..))”)

Spring中AOP的通知类型

  1. @Around(“pointCut()”) :环绕通知,此注解标注的通知方法在目标方法前、后都被执行
  2. @Before(“pointCut()”):前置通知,此注解标注的通知方法在目标方法前被执行
  3. @After(“pointCut()”):后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
  4. @AfterReturning(“pointCut()”): 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
  5. @AfterThrowing(“pointCut()”): 异常后通知,此注解标注的通知方法发生异常后执行

设计模式

  1. 工厂设计模式 : Spring 使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。
  2. 代理设计模式 : Spring AOP 功能的实现。
  3. 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  4. 模板方法模式 : SpringjdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操 作的类,它们就使用到了模板模式。
  5. 包装器设计模式 :我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  6. 观察者模式:Spring 事件驱动模型就是观察者模式很经典的一个应用。
  7. 适配器模式 :Spring AOP 的增强或通知 (Advice) 使用到了适配器模式、Spring MVC 中也是用到了 适配器模式适配 Controller

SpringMVC的执行流程

  1. 用户发送请求至前端控制器 DispatcherServlet
  2. DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
  3. 处理器映射器找到具体的处理器(可以根据 xml 配置、注解进行查找),生成处理器对象及处理器拦截 器(如果有则生成)一并返回给 DispatcherServlet
  4. DispatcherServlet 调用 HandlerAdapter 处理器适配器。
  5. HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)。
  6. Controller 执行完成返回 ModelAndView
  7. HandlerAdaptercontroller 执行结果 ModelAndView 返回给 DispatcherServlet
  8. DispatcherServletModelAndView 传给 ViewReslover 视图解析器。
  9. ViewReslover 解析后返回具体 View
  10. DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户。

SpringBoot启动流程

  1. @SpringBootApplication
  2. SpringApplication.run()
  3. 实例化 ApplicationContext
  4. 加载 @EnableAutoConfiguration
  5. Bean 实例化,托管给 spring容器

SpringBoot Starter有什么用

Spring Boot Starter 的作用是简化和加速项目的配置和依赖管理。

  1. Spring Boot Starter 可以理解为一种预配置的模块,它封装了特定功能的依赖项和配置, ,开发者只需引入相关的 Starter 依赖,无需手动配置大量的参数和依赖项。常用的启动器包括 spring-boot-starter-web(用于Web应用)、spring-boot-starter-data-jpa(用于数据库访问)等。 引入这些启动器后,Spring Boot 会自动配置所需的组件和 Bean,无需开发者手动添加大量配置。
  2. Starter还管理了相关功能的依赖项,包括其他Starter和第三方库,确保它们能够良好地协同工作,避免版本冲突和依赖问题。
  3. Spring Boot Starter 的设计使得应用可以通过引入不同的Starter来实现模块化的开发。每个Starter都关注一个特定的功能领域,如数据库访问、消息队列、Web开发等。
  4. 开发者可以创建自定义的 Starter,以便在项目中共享和重用特定功能的配置和依赖项。

Spring,Spring MVC,Spring Boot的区别

  1. spring 是容器,服务层框架
  2. springmvc 是基于 mvc 的web 框架,servlet
  3. springboot 快速构建,快速部署

Spring 循环依赖是怎么解决的

什么是循环依赖

​ 两个或者两个以上的 bean 互相持有对方,最终形成闭环。比如 Bean A 依赖于 Bean B,而 Bean B 又依赖于 Bean A,形成了一个循环依赖关系。这种情况下,如果不处理,会导致 Spring 容器无法完成 Bean 的初始化,从而抛出循环依赖异常。

怎么检测是否存在循环依赖

​ 检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean打标,如果递归调用回来发现正在创建中的话,即说明产生循环依赖了。

如何解决

  • 构造器循环依赖:Spring容器在创建Bean时,如果遇到循环依赖,通常是无法处理的,因为这会导致无限递归创建Bean实例。所以,构造器注入是不支持循环依赖的。

  • 字段注入或Setter注入:使用了三级缓存来解决循环依赖问题。

    • 首先,Spring容器会创建一个Bean的原始实例,但此时Bean的属性尚未设置,这个实例被存放在一级缓存中。
    • 当Bean的属性被设置时,如果属性值是其他Bean的引用,Spring会去检查二级缓存,看是否已经有该Bean的引用存在。
    • 如果二级缓存中没有,Spring会尝试创建这个被引用的Bean,并将其放入三级缓存。
    • 最后,当Bean的属性设置完成后,原始的Bean实例会被放入二级缓存,供其他Bean引用
  • 使用@Lazy注解:通过@Lazy注解,可以延迟Bean的加载,直到它被实际使用时才创建,这可以避免一些循环依赖的问题。

Bean的生命周期

背诵技巧:通天(填)A(Aware),B始(使)毁

​ Spring Bean的生命周期,其实就是Spring容器从创建Bean到销毁Bean的整个过程。这里面有几个关键步骤:

  1. 实例化Bean: Spring容器通过构造器或工厂方法创建Bean实例。
  2. 设置属性:容器会注入Bean的属性,这些属性可能是其他Bean的引用,也可能是简单的配置值。
  3. 检查Aware接口并设置相关依赖:如果Bean实现了BeanNameAwareBeanFactoryAware接口,容器会调用相应的setBeanNamesetBeanFactory方法。
  4. BeanPostProcessor的第一次调用:在Bean初始化之前,Spring会调用所有注册的BeanPostProcessorpostProcessBeforeInitialization方法。
  5. 初始化Bean: 如果Bean实现了InitializingBean接口,容器会调用其afterPropertiesSet方法。同时,如果Bean定义了init-method,容器也会调用这个方法。
  6. BeanPostProcessor的第二次调用:在Bean初始化之后,容器会再次调用所有注册的BeanPostProcessorpostProcessAfterInitialization方法。
  7. 使用Bean:此时,Bean已经准备好了,可以被应用程序使用了。
  8. 处理DisposableBeandestroy-method:当容器关闭时,如果Bean实现了DisposableBean接口或者定义了destroy-method,容器会调用其destroy方法。
  9. Bean销毁:最后,Bean被Spring容器销毁,结束了它的生命周期。

Mybatis

$和# 区别

  1. $是字符串拼接
  2. #是参数传递,对sql语句进行了预编译,解决了sql注入

​ sql注入(SQL Injection)是一种常见的Web安全漏洞,形成的主要原因是web应用程序在接收相关数据参数时未做好过滤,将其直接带入到数据库中查询,导致攻击者可以拼接执行构造的SQL语句。

如”or “a”=”a

分页实现

基础分页

流程

注意:要查询数据库两次

  1. 查询全表数据
  2. SQL语句 limit

Pagehelper插件(⭐业务)

  1. 在 maven 文件中引入 pagehelper 依赖;
  2. 创建分页结果封装类 PageBean,包含两个参数,total 总记录数,rows 数据列表;
  3. 在 serviceImpl 类下的 分页方法中调用 PageHelper.startPage(page,pageSize);
  4. 返回 PageBean 对象。

在pom.xml引入依赖

1
2
3
4
5
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>

创建分页结果封装类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;

/**
* 分页查询结果封装类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
private Long total;//总记录数
private List rows;//数据列表

}

ServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public PageBean page(Integer page, Integer pageSize,String name, Short gender, LocalDate begin, LocalDate end) {
//1. 设置分页参数
PageHelper.startPage(page,pageSize);

//2. 执行查询
List<Emp> empList = empMapper.list(name, gender, begin, end);
Page<Emp> p = (Page<Emp>) empList;

//3. 封装PageBean对象
PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
return pageBean;
}


Mapper

1
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

Mapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--条件查询-->
<select id="list" resultType="com.itheima.pojo.Emp">
select *
from emp
<where>
<if test="name != null and name != ''">
name like concat('%', #{name}, '%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>

动态sql的作用

特点

  1. 多条件查询
  2. 选择性插入
  3. 选择性修改

动态SQL的标签

where、set、if、trim