知识体系总结(八)SSM框架体系

news2024/11/18 11:24:20

文章目录

  • Spring基础
    • 1-1、Spring、SpringMVC、Mybatis与SpringBoot的区别
    • 1-2、Spring中常用的注解及作用
    • 1-3、Spring 框架中用到了哪些设计模式?
  • Spring IoC 、 DI、Bean
    • 2-1、Spring IoC是什么,有什么好处,Spring中是怎么实现的?
    • 2-2、声明Bean的注解有哪些?
      • 2-3、@Component 和 @Bean 的区别是什么?
      • 2-4、注入Bean的注解有哪些,@Autowired与@Resource的区别在哪?
      • 2-5、Bean是线程安全的吗?
      • 2-6、Bean的生命周期是怎么样的?
    • 2-7、Spring如何解决循环依赖问题?
  • Spring AoP
    • 3-1、Spring AoP是怎么实现的?
    • 3-2、CGLIB和JDK动态代理的实现区别
    • 3-3、Spring AOP 和 AspectJ AOP 有什么区别?
  • Spring MVC
    • 4-1 SpringMVC的核心组件有哪些?
    • 4-2 SpringMVC的工作原理?
    • 4-3 SpringMVC 统一 / 全局异常处理怎么做?
    • 4-4 拦截器和过滤器有什么区别?
  • Spring事务
    • 编程式事务管理
    • 声明式事务管理
    • 5-1 Spring管理事务的方式有几种?
    • 5-2 Spring事务中有哪几种事务传播(propagation)行为?
    • 5-3 Spring 事务中的隔离级别有哪几种?
  • SpringBoot
    • 6-1 Spring启动时的自动配置原理
    • 6-2 SpringBoot Starter(启动器)工作原理是什么?
  • Mybatis

Spring基础

1-1、Spring、SpringMVC、Mybatis与SpringBoot的区别

  • Spring是一个轻量级的Java企业级开发框架,提供了很多功能和特性,如:
    • 控制反转(IOC)
    • 依赖注入(DI)
    • 面向切面编程(AOP)
    • Spring事务管理
  • Spring MVC则是Spring框架的一部分,专注于Web应用程序的开发,提供如下功能:
    • 接收请求
    • 设置请求拦截器
    • 响应数据
    • 全局异常处理
  • Mybatis则是数据持久层框架,与数据库打交道,可以使用简单的XML或者注解配置和映射数据库表格中的原始信息,完成系统中Java实体类与数据库中记录的映射
  • Spring Boot是一个简化了Spring应用开发的框架,通过起步依赖和自动配置,大大简化了spring配置的流程,使得开发者可以更专注于业务逻辑的实现。

在这里插入图片描述

1-2、Spring中常用的注解及作用

  1. 配置Bean相关:
  • @Autowire:让Spring容器自动装配Bean到类中。
  • @ComponentScan:通过自动扫描机制来发现和注册满足条件的组件。
  • @Configuration:用于指定配置类,替代传统的XML配置文件。
  • @Bean:用于在@Configuration类中声明Bean定义,供Spring容器管理。
  • @Qualifier:与@Autowired一起使用,通过指定Bean名称解决自动装配的歧义性。
  • @Value:用于注入简单值或表达式到Bean的属性。
  • @Scope:用于指定Bean的作用域,如单例(Singleton)或原型(Prototype)。
  • @ConfigurationProperties:用于绑定配置文件中的属性到Java类的字段上,支持批量绑定。
  1. SpringMVC相关:
  • @Component:通用注解,标明该类是应该交由Spring管理的。如果一个Bean不知道属于哪个层,使用该注解。
  • @RequestMapping:用于将HTTP请求映射到控制器的处理方法,例如:@RequestMapping(“/books”)
  • @PathVariable:用于获取URL路径变量值并映射到方法参数。
    // 处理URL: /books/{id}
    @GetMapping("/{id}")
    public String getBookById(@PathVariable Long id) {
        // 处理方法逻辑
        return "book_details";
    }
  • @RequestParam:用于获取请求参数的值并映射到方法参数。
    // 处理URL: /books?category=fiction
    @GetMapping
    public String getBooksByCategory(@RequestParam("category") String category) {
        // 使用category进行业务逻辑处理
        // ...
        return "books_by_category";
    }
  • @ResponseBody:用于将方法返回值直接作为HTTP响应的内容返回。
@RestController
@RequestMapping("/api")
public class BookController {

    @PostMapping("/books")
    public ResponseEntity<String> createBook(@RequestBody Book book) {
        // 处理从请求体中解析出来的 Book 对象
        // ...
        return new ResponseEntity<>("Book created successfully", HttpStatus.CREATED);
    }
}
  • @Controller:控制层注解,处理HTTP请求并返回响应。此外还有@RestController注解,它是@Controller和@ResponseBody的合集。
  • @Service:用于标识服务层类,通常用于注解Service组件。
  • @Repository:用于标识数据访问层类,通常用于注解DAO组件。
  • @Transactional:用于标识事务方法,启用方法级别的事务管理。

1-3、Spring 框架中用到了哪些设计模式?

  1. 工厂模式:Spring中使用BeanFactory或者ApplicationContext创建Bean对象。工厂模式对客户隐藏构造细节,只需要客户提供产品参数,即返回给客户产品对象。
  2. 单例模式:Spring中Bean的默认作用域都是singleton(单例),Spring中通过ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。使用单例模式的好处在于:对于频繁使用的对象,可以省略创建对象所花费的时间,减少系统开销,并减轻GC压力。
  3. 代理模式:Spring AOP基于动态代理实现。代理对象实现增强的业务逻辑。如果待增强对象实现了接口,采用JDK 动态代理实现。如果待增强对象没有实现接口,则使用CGlib动态代理。
  4. 模板方法:模板方法模式是一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。Spring框架中大量应用了模板方法,如HibernateTemplate 等以 Template 结尾的对数据库操作的类。JdbcTemplate、
  5. 监听者模式:Spring事件发布 - 监听,应用到了监听者模式,但事件发生时,监听器判断是否是自身监听的对象,从而决定是否执行监听回调。
  6. 适配器模式:Spring AOP中,通知类型有多种,前置、后置、环绕、销毁前、异常时,所有的非环绕通知都需要调用AdvisorAdapter转为环绕通知,然后再交给方法拦截器(MethodInterceptor)。
  7. 责任链模式:Spring AOP中 一个对象配置了多个通知,是按照责任链模式来执行。责任链模式中,每个节点都可以选择处理任务或者直接将其移交给下一个节点。与此类似的还有SpringMVC中的拦截器、JDK中的过滤器。

Spring IoC 、 DI、Bean

2-1、Spring IoC是什么,有什么好处,Spring中是怎么实现的?

IoC(Inversion of Control:控制反转) 是一种设计思想,是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理,即将对象的创建和管理的权力交由Spring容器。

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/=或者注解即可,完全不用考虑对象是如何被创建出来的。简化应用开发,利用实现分层解耦。

在这里插入图片描述

在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value)注册表,Map 中存放的是各种Bean对象,key就是Bean的名称(或ID),value 是 Bean 的定义信息,包括类名、依赖关系、初始化方法、销毁方法等。

2-2、声明Bean的注解有哪些?

简单来说,Bean 代指的就是那些被 IoC 容器所管理的对象。

Bean的配置可以通过XML文件配置,也可以通过注解在设置。比如:

  • @Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用* @Component 注解标注。
  • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
  • @Repository(仓库) : 对应持久层即 Dao 层,主要用于数据库相关操作。

2-3、@Component 和 @Bean 的区别是什么?

  1. @Component 注解作用于类,而@Bean注解作用于方法。
  2. @Component通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我。
  3. @Bean 注解比 @Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

2-4、注入Bean的注解有哪些,@Autowired与@Resource的区别在哪?

Spring 内置的 @Autowired 以及 JDK 内置的 @Resource 和 @Inject 都可以用于注入 Bean。

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。Autowired 默认的注入方式为byType(根据类型进行匹配),
  • @Resource默认注入方式为 byName(根据名称进行匹配)。

当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。

  • @Autowired 可以通过 @Qualifier 注解来显式指定名称
  • @Resource可以通过 name 属性来显式指定名称。

举个例子,SmsService 接口有两个实现类: SmsServiceImpl1和 SmsServiceImpl2,且它们都已经被 Spring 容器所管理。

// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入  SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")
private SmsService smsService;


// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式)
@Resource(name = "smsServiceImpl1")
private SmsService smsService;

2-5、Bean是线程安全的吗?

Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。

在多例(prototype)的作用域下,每次获取都创建一个新的bean实例,不存在资源竞争问题,所有没有线程安全问题。

在单例(singleton)作用域下,IoC容器只有唯一的bean实例,可能存在资源竞争问题,如果bean有状态即包含可变的成员变量,那么就存在线程安全问题。

对于有状态且为单例Bean的线程安全问题,常见的有两种解决办法:

  1. 在Bean中尽量避免定义可变的成员 变量
  2. 在类中定义ThreadLocal,将需要的成员变量保存在TheadLoacl使其线程私有化。

2-6、Bean的生命周期是怎么样的?

  1. IoC容器找到配置文件中Spring Bean的定义
  2. IoC容器利用Java 反射创建一个Bean的实例
  3. 如果涉及到一些Bean的属性赋值如使用了@Value注解,则利用set()方法设置属性值。
  4. 如果Bean实现了BeanNameAware接口,则调用setBeanName方法,传入Bean的名字。Aware接口是在编译阶段内置在Bean中,用来与IoC容器打交道,获取Bean的相关信息时用的。4 - 7 都是一些Aware接口,了解Aware接口的概念即可,不用记得那么细致。
  5. 如果Bean实现了BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
  6. 如果 Bean 实现了 BeanFactoryAware 接口,调用 setBeanFactory()方法,传入 BeanFactory对象的实例。
  7. 如果实现了其他 *.Aware接口,就调用相应的方法。
  8. 如果有和加载这个Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法。即初始化前的Bean后处理器
  9. 如果 Bean 实现了InitializingBean接口,执行afterPropertiesSet()方法。InitializingBean是与Aware类似 的接口,是与Bean耦合的,InitializingBean接口会执行初始化逻辑
  10. 如果 Bean 在配置文件中的定义包含 init-method 属性,则执行init-method 指定的方法。8 - 10 是Bean初始化时可以设置的三种回调,它们的顺序分别是 Bean初始化前的后处理器、InitializingBean内置接口、配置属性init - method
  11. 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法即销毁前的Bean后处理器
  12. 如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。DisposableBean 接口是与InitializingBean类似的耦合接口
  13. 如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。11-13是与初始化时相对应的,在销毁前的3种回调,它们的执行顺序与初始化是一样的,即 后处理器 、耦合接口、配置属性

上边列举的Bean的生命周期有点儿过长了:
简单来记忆:

Bean生命周期的主要脉络包括:

  • 1、Bean配置
  • 2、Bean实例化
  • 3、Bean初始化
  • 5、Bean的使用
  • 4、Bean销毁

展开来讲包括:

  • 1、找到配置文件中Bean定义
  • 2、基于反射实例化Bean
  • 3、如果Bean实现了Aware相关耦合接口,则执行对应实现方法
  • 4、Bean初始化:
    • Bean后处理器:前置处理
    • 耦合接口: InitializingBean
    • Bean配置属性:init-method指定的方法
    • Bean后处理器:后置处理
  • 5、Bean的使用
  • 6、Bean销毁:
    • Bean后处理器:销毁前置处理
    • 耦合接口: DisposableBean
    • Bean配置属性:destroy-method指定的方法
      在这里插入图片描述

2-7、Spring如何解决循环依赖问题?

循环依赖有三种形态:

  1. 相互依赖,也就是 A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。
  2. 间接依赖,也就是 A 依赖 B,B 依赖 C,C 又依赖 A,形成了循环依赖。
  3. 自我依赖,也是 A 依赖 A 形成了循环依赖。

Spring设计了三级缓存来解决循环依赖问题,一级缓存存放完整可用的Bean实例,二级缓存存储实例化以后,还没设置属性值的Bean实例,即Bean中的依赖注入还没有处理,三级缓存用来存放Bean工厂,它主要用来生成原始Bean对象,并且将其放入二级缓存中,三级缓存的核心思想就是把Bean的依赖注入和Bean的实例化进行分离,采用一级缓存缓存完成可用的实例,采用二级缓存

Spring AoP

AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

3-1、Spring AoP是怎么实现的?

Spring AoP是基于动态代理的方式实现,具有实现方式又分为了:

  • 1、基于JDK 的动态代理:对于实现了接口的目标对象,Spring使用JDK动态代理来创建代理对象。JDK动态代理是通过Java原生的Proxy类来实现的。代理对象实现了目标接口,并在InvocationHandler的invoke方法中添加了增强逻辑,原方法基于反射实现,method.invoke(‘待增强对象’, ‘方法参数’);

    • 具体实现原理:
      • 1、代理对象必须实现InvocationHandler接口,JDK在实现时是继承了Proxy类,提供了InvocationHandler的构建方法,在执行时通过super,传入InvocationHandler。
      • 2、使用Proxy.newProxyInstance产生代理对象,代理对象是基于ASM(字节码操作框架)技术,动态生成的字节码,因此需要传入类加载器,将字节码加载为对象。
      • 3、接口方法的获取是通过反射的方式,即从类的字节码中调用getMethod方法得到的,为了避免多次调用的getMethod的开销,代理对象内部使用静态成员保存了方法,并通过静态代码块进行了初始化赋值。
      • 4、为了处理有返回值的方法,代理对象中的返回值为Object对象。方法中对于异常的捕获和处理,分为了运行时异常和受检时异常,对于运行时异常直接抛出,对于受检异常,将其包装为UndeclaredThrowableException后,再抛出。
      • 5、jdk反射优化,接口方法增强时,采用了反射的方式调用方法,这样性能是有损耗的,jdk内部对此进行了优化,当调用次数到第17次时,jdk内部会生成一个有该方法的代理对象,直接调用该代理对象的方法,而不再使用反射的形式调用。
  • 2、基于CGLib的动态代理:CGLib动态代理采用继承 + 方法拦截器的方式,针对可继承的目标类进行增强。

    • 具体实现原理:
      • 1、生成代理类:当目标类需要被代理时,CGLIB会在运行时生成一个代理类,该代理类继承自目标类,成为目标类的子类。
      • 2、拦截器:在CGLIB中,代理的逻辑由一个拦截器(MethodInterceptor)来实现,拦截器负责在代理类的方法调用前后执行额外的逻辑。拦截器类似于JDK动态代理中的InvocationHandler。
      • 3、方法调用的重定向:在代理类的方法调用时,CGLIB会将方法的调用重定向到拦截器的intercept()方法中。在intercept()方法中,可以实现对目标方法的增强逻辑,并调用目标方法。
      • 4、代理对象创建:通过字节码生成技术,CGLIB将代理类的定义转换为字节码,并使用ClassLoader加载字节码,最终生成代理对象。

3-2、CGLIB和JDK动态代理的实现区别

  1. 原理和实现方式:
    JDK动态代理:JDK动态代理是通过Java原生的java.lang.reflect.Proxy类和InvocationHandler接口来实现的。在运行时,JDK动态代理通过生成目标接口的代理对象,并通过InvocationHandler的invoke()方法来实现对目标方法的拦截和增强。
    CGLIB动态代理:CGLIB动态代理是通过CGLIB库,利用字节码生成技术,在运行时生成目标类的子类作为代理类。在子类中,CGLIB通过生成MethodProxy对象实现对目标方法的拦截和增强。

  2. 代理类型:
    JDK动态代理:JDK动态代理只能代理实现了接口的目标类。如果目标类没有实现任何接口,就无法使用JDK动态代理进行代理。
    CGLIB动态代理:CGLIB动态代理可以代理没有实现接口的目标类。它通过生成目标类的子类来实现代理,因此对于没有接口的类也能够代理。

  3. 性能:
    JDK动态代理:JDK动态代理在调用代理方法时,涉及到反射调用,有一定的性能开销。代理效率相对较低,尤其在代理方法较多时性能下降较明显。
    CGLIB动态代理:CGLIB动态代理在调用代理方法时,通过直接调用生成的子类的方法,无需反射调用,因此相对于JDK动态代理,性能更高。特别适用于代理方法较多或代理对象创建较频繁的情况。

  4. 依赖和兼容性:
    JDK动态代理:JDK动态代理依赖于Java原生的java.lang.reflect.Proxy类,对于Java平台的兼容性较好,无需额外引入第三方库。
    CGLIB动态代理:CGLIB动态代理依赖于CGLIB库,使用时需要引入相应的依赖。CGLIB动态代理在Java平台上运行良好,但在其他Java虚拟机(JVM)上可能存在兼容性问题。

3-3、Spring AOP 和 AspectJ AOP 有什么区别?

  • Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。
    Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比 Spring AOP 快很多。

Spring MVC

4-1 SpringMVC的核心组件有哪些?

  • DispacherServlet:核心的中央处理器,负责接收、分发并响应客户端请求。
  • HandlerMapping:处理器映射器,根据URL去匹配查找能处理的Handler,并会将请求涉及的拦截器和Handler一起封装。
  • HandlerAdapter:处理器适配器,根据HandlerMapping找到的handler,适配执行对应的Handler
  • Handler:请求处理器
  • ViewResolver:视图解析器,根据Handler返回的视图 / 逻辑视图,解析并渲染真正的视图,并传递给DispatcherServlet,以响应客户端。

4-2 SpringMVC的工作原理?

在这里插入图片描述
流程说明(重要):

  1. 客户端(浏览器)发送请求, DispatcherServlet拦截请求。
  2. DispatcherServlet 根据请求信息调用 HandlerMapping 。HandlerMapping 根据 uri 去匹配查找能处理的 Handler(也就是我们平常说的 Controller 控制器) ,并会将请求涉及到的拦截器和 Handler 一起封装。
  3. DispatcherServlet 调用 HandlerAdapter适配器执行 Handler 。
  4. Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给DispatcherServlet,ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model 是返回的数据对象,View 是个逻辑上的 View。
  5. ViewResolver 会根据逻辑 View 查找实际的 View。
  6. DispaterServlet 把返回的 Model 传给 View(视图渲染)。
  7. 把 View 返回给请求者(浏览器)

4-3 SpringMVC 统一 / 全局异常处理怎么做?

使用@ControllerAdvice + @ExceptionHandler 这两个注解的统一异常处理。

@ControllerAdvice即控制器增强,用于处理控制层的异常处理逻辑,而其他层(Service、Dao)只需要不断往外抛出异常即可,不需要考虑异常处理代码。

@ExceptionHandler:可以指定所要拦截的异常类型,一般我们分为运行时异常和自定义异常。

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    @ExceptionHandler(BaseException.class)
    public ResponseEntity<?> handleAppException(BaseException ex, HttpServletRequest request) {
      //......
    }

    @ExceptionHandler(value = ResourceNotFoundException.class)
    public ResponseEntity<ErrorReponse> handleResourceNotFoundException(ResourceNotFoundException ex, HttpServletRequest request) {
      //......
    }
}

这种异常处理方式下,会给所有或者指定的 Controller 织入异常处理的逻辑(AOP),当 Controller 中的方法抛出异常的时候,由被@ExceptionHandler 注解修饰的方法进行处理。

ExceptionHandlerMethodResolver 中 getMappedMethod 方法决定了异常具体被哪个被 @ExceptionHandler 注解修饰的方法处理异常。

@Nullable
	private Method getMappedMethod(Class<? extends Throwable> exceptionType) {
		List<Class<? extends Throwable>> matches = new ArrayList<>();
    //找到可以处理的所有异常信息。mappedMethods 中存放了异常和处理异常的方法的对应关系
		for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) {
			if (mappedException.isAssignableFrom(exceptionType)) {
				matches.add(mappedException);
			}
		}
    // 不为空说明有方法处理异常
		if (!matches.isEmpty()) {
      // 按照匹配程度从小到大排序
			matches.sort(new ExceptionDepthComparator(exceptionType));
      // 返回处理异常的方法
			return this.mappedMethods.get(matches.get(0));
		}
		else {
			return null;
		}
	}

从源代码看出:getMappedMethod()会首先找到可以匹配处理异常的所有方法信息,然后对其进行从小到大的排序,最后取最小的那一个匹配的方法(即匹配度最高的那个)。

4-4 拦截器和过滤器有什么区别?

在这里插入图片描述
Filter接口需要我们重写三个方法:

init:初始化,只执行一次
doFilter:拦截请求后调用,可以调用多次,可以在这里通过执行chain.doFilter()放行请求。
destroy:销毁方法,只调用一次。
在这里插入图片描述
在这里插入图片描述

  1. 从依赖关系上讲,拦截器属于SpringMVC框架,而过滤器属于Servlet体系。
  2. 从具体使用上讲,两者的接口规范不同,过滤器需实现Filter接口,过滤器执行有三个阶段 init()、doFilter()、destroy()。而拦截器需实现HandleInterceptor接口,也有三个阶段:preHandler()、postHandler()和afterCompletion()。
  3. 从执行顺序上讲:所有的请求都先被过滤器链Filter拦截,放行后,请求被DispatcherServlet分发,进入拦截器链。一个畅行的请求,它经历的阶段为:过滤器1 拦截前 -> 过滤器2 拦截前 …… Servlet分发器-> 拦截器1拦截前 -> 拦截器2 拦截前 …… 最后的拦截器 拦截后 ……->第一个拦截器 -> Servlet分发器 -> 最后的过滤器 拦截后 ……->第一个过滤器
  4. 从功能上讲:过滤器主要用于对请求和响应进行过滤和处理,例如字符编码处理、非法请求过滤、响应加密等。拦截器主要用于实现一些与业务逻辑相关的功能,例如身份认证、权限校验、日志记录、性能监控等。
public void init(FilterConfig filterConfig) throws ServletException;

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

public void destroy();

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception;

void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception;

Spring事务

编程式事务管理

编程式事务管理:通过 TransactionTemplate或者TransactionManager手动管理事务。

使用TransactionTemplate进行编程式事务管理的示例代码如下:

@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

                try {

                    // ....  业务代码
                } catch (Exception e){
                    //回滚
                    transactionStatus.setRollbackOnly();
                }

            }
        });
}

使用 TransactionManager 进行编程式事务管理的示例代码如下:

@Autowired
private PlatformTransactionManager transactionManager;

public void testTransaction() {

  TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
          try {
               // ....  业务代码
              transactionManager.commit(status);
          } catch (Exception e) {
              transactionManager.rollback(status);
          }
}

声明式事务管理

采用注解@Transactional通过 AOP 实现:

@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
	  //do something
	  B b = new B();
	  C c = new C();
	  b.bMethod();
	  c.cMethod();
}

5-1 Spring管理事务的方式有几种?

  • 编程式事务:在代码中硬编码(不推荐使用) : 通过 TransactionTemplate或者 TransactionManager 手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助。
  • 声明式事务:在 XML 配置文件中配置或者直接基于注解(推荐使用) : 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)

5-2 Spring事务中有哪几种事务传播(propagation)行为?

事务传播行为是为了解决业务层方法之间互相调用的事务问题。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

正确的事务传播行为可能的值如下:

  • 1.TransactionDefinition.PROPAGATION_REQUIRED:使用的最多的一个事务传播行为,我们平时经常使用的@Transactional注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。即:REQUIRED模式下,后来执行的事务融入之前的事务
  • 2.TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。即:REQUIRED_NEW模式下,利用线程同步机制,先阻塞之前事务的线程,另起一个线程执行新的事务,事务提交后,再通知唤醒之前的事务,这种方式避免了后边事务的回归导致的先前事务的回滚
  • 3.TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。底层数据库在实现时,采用了save point a,保存点,当新事务执行完毕,再恢复保存点处 back to a
  • 4.TransactionDefinition.PROPAGATION_MANDATORY如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常,即强制要求事务环境。(mandatory:强制性)这个使用的很少。

若是错误的配置以下 3 种事务传播行为,事务将不会发生回滚:

  1. TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。支持事务,有事务就加入支持,没有事务就按非事务方式执行,适合查询 / 只读业务
  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。即不支持事务,如果当前存在事务,挂起阻塞
  3. TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

5-3 Spring 事务中的隔离级别有哪几种?

TransactionDefinition 接口中定义了五个表示隔离级别的常量:
其实就是在数据库事务隔离级别的基础上,加了默认隔离级别与数据库事务隔离级别保持一致。

  • 1、TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
  • 2、TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • 3、TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • 4、TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • 5、TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

SpringBoot

6-1 Spring启动时的自动配置原理

1、Spring启动类会加@SpringBootApplication注解,该注解可以看作是三个主要的注解@Configuration,@ComponentScan和@EnableAutoConfiguration的集合。
2、@Configuration声明了启动类为主配置类,@ComponentScan则会扫描主配置类及其所在包下所有类,将@Component注解标识的类或@Component的复合注解,如@Service、@Controller、@Repository等加入到Spring容器。
3、重点是@EnableAutoConfiguration注解,它可以看作是@AutoConfigurationPackage和@Import注解的集合,@AutoConfigurationPackage 作用是告诉Spring Boot 自动配置类的扫描范围,默认会限定在主类所在的包及其子包中搜索自动配置类。@Import注解中导入的AutoConfigurationImportSelector则会调用SpringFactoryLoader将META-INF目录下spring.factory文件中声明的Bean都加入到Spring容器中。

6-2 SpringBoot Starter(启动器)工作原理是什么?

Spring Boot在启动时:

  • Spring Boot 在启动时会去依赖的 Starter 包中寻找 resources/META-INF/spring.factories 文件,
    然后根据文件中配置的 Jar 包去扫描项目所依赖的 Jar 包。
  • 根据 spring.factories 配置加载 AutoConfigure 类
  • 根据 @Conditional 注解的条件,进行自动配置并将 Bean 注入 Spring容器

Spring Boot 在启动的时候,按照约定去读取 Spring Boot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 Spring Boot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可。

Mybatis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/837603.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Kali渗透基础》13. 无线渗透(三)

kali渗透 1&#xff1a;无线通信过程1.1&#xff1a;Open 认证1.2&#xff1a;PSK 认证1.3&#xff1a;关联请求 2&#xff1a;加密2.1&#xff1a;Open 无加密网络2.2&#xff1a;WEP 加密系统2.3&#xff1a;WPA 安全系统2.3.1&#xff1a;WPA12.3.2&#xff1a;WPA2 3&#…

修复 Adob​​e After Effects 预览无法工作/播放的方法技巧

Adobe After Effects 允许您预览视频和音频&#xff0c;而无需将其渲染为最终输出。当您无法在此应用程序中预览视频和音频时&#xff0c;一定会感到沮丧。不过不用担心&#xff0c;您可以尝试以下方法来修复 After Effects 预览不起作用的问题。 技巧1&#xff1a;重启After …

SHEIN还说TEMU,2023跨境电商怎么选?

2023年要说跨境热门的平台有哪些&#xff0c;SHEIN与TEMU应该是名列前茅的。这两家一直以来给人感觉也都是比较相似的&#xff0c;他们的跨境斗法从未停歇。其实两者有相似之处&#xff0c;也有不同之处!作为跨境玩家&#xff0c;我们应该如何选择适合自己的平台呢?往下看。 一…

Qt 6. 其他类调用Ui中的控件

1. 把主类指针this传给其他类&#xff0c;tcpClientSocket new TcpClient(this); //ex2.cpp #include "ex2.h" #include "ui_ex2.h"Ex2::Ex2(QWidget *parent): QDialog(parent), ui(new Ui::Ex2) {ui->setupUi(this);tcpClientSocket new TcpClient…

一百四十一、Kettle——kettle8.2在Windows本地开启carte服务以及配置子服务器

一、目的 在kettle建好共享资源库后&#xff0c;为了给在服务器上部署kettle的carte服务躺雷&#xff0c;先在Windows本地测试一下怎么玩carte服务 二、Kettle版本以及在Windows本地安装路径 kettle版本是8.2 pdi-ce-8.2.0.0-342 kettle本地安装路径是D:\j…

【动态规划刷题 4】礼物的最大价值下降路径最小和

礼物的最大价值 在一个 m*n 的棋盘的每一格都放有一个礼物&#xff0c;每个礼物都有一定的价值&#xff08;价值大于 0&#xff09;。你可以从棋盘的左上角开始拿格子里的礼物&#xff0c;并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值…

Flutter iOS 集成使用 fluter boost

在 Flutter项目中集成完 flutter boost&#xff0c;并且已经使用了 flutter boost进行了路由管理&#xff0c;这时如果需要和iOS混合开发&#xff0c;这时就要到 原生端进行集成。 注意&#xff1a;之前建的项目必须是 Flutter module项目&#xff0c;并且原生项目和flutter m…

Kotlin~Visitor访问者模式

概念 将数据结构和操作分离&#xff0c;使操作集合可以独立于数据结构变化。 角色介绍 Visitor&#xff1a;抽象访问者&#xff0c;为对象结构每个具体元素类声明一个访问操作。Element&#xff1a;抽象元素&#xff0c;定义一个accept方法ConcreteElement&#xff1a;具体元…

HTML编码

目录 1.HTML编码概述2.实体编码3.URLcode编码4.unicode编码5.解码实例 1.HTML编码概述 通常一个网页中可解析的总共有三种编码&#xff0c;每种编码都能用来代替表示字符&#xff0c;按解析顺序依次是“html实体编码”“urlcode码”“Unicode码”&#xff0c;在执行过程中会在…

Flowable-顺序流

目录 顺序流标准顺序流定义图形标记XML内容使用示例 条件顺序流定义图形标记XML内容界面操作 默认顺序流定义图形标记XML内容使用示例视频教程 顺序流 顺序流是一端带有箭头的实线&#xff0c;可在流程图中连接流程内的各个元素&#xff0c;并显示各个元素的执行顺序。 Flowa…

Flink学习教程

最近因为用到了Flink&#xff0c;所以博主开了《Flink教程》专栏来记录Flink的学习笔记。 【Apache Flink v1.16 中文文档】 【官网 - Apache Flink v1.3 中文文档】 一、基础 参考链接如下&#xff1a; Flink教程&#xff08;01&#xff09;- Flink知识图谱Flink教程&…

[Docker实现测试部署CI/CD----自由风格的CI操作[最终架构](5)]

目录 11、自由风格的CI操作&#xff08;最终&#xff09;Jenkins容器化实现方案修改 docker.sock 权限修改 Jenkins 启动命令后重启 Jenkins构建镜像推送到Harbor修改 daemon.json 文件Jenkins 删除构建后操作Jenkins 添加 shell 命令重新构建 Jenkins通知目标服务器拉取镜像目…

Java阶段五Day18

Java阶段五Day18 文章目录 Java阶段五Day18缓存方案面试题整理 项目功能新增审核业务流程图 账户账户表格和ER图账号服务功能账号的创建当前实现功能时序图&#xff08;对应全景图&#xff09; 抢单相关时序图供应商和需求单 附录布隆过滤器 缓存方案 面试题整理 目标&#xf…

【Unity3D应用案例系列】Unity3D中实现文字转语音的工具开发

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在开发中&#xff0c;会遇到将文字转语音输出的需求&#xff0…

[每周一更]-(第57期):用Docker、Docker-compose部署一个完整的前后端go+vue分离项目

文章目录 1.参考项目2.技能点3.GO的Dockerfile配置后端的结构如图Dockerfile先手动docker调试服务是否可以启动报错 4.Vue的Dockerfile配置前端的结构如图nginx_docker.confDockerfile构建 5.docker-compose 整合前后端docker-compose.yml错误记录&#xff08;1&#xff09;ip端…

宇树Unitree Z1机械臂使用教程

宇树Unitree Z1机械臂使用教程 作者&#xff1a;Herman Ye Galbot Auromix Auromix是一个机器人爱好者组织&#xff0c;欢迎参与我们Github上的开源项目 更新日期&#xff1a;2023/08/04 注意&#xff1a;此文档在该日期下测试有效。 以下内容参考宇树官方的Z1 Docs。 由宇树…

idea调节文字大小、日志颜色、git改动信息、单击打开代码覆盖原标签问题

idea调节菜单栏文字大小&#xff1a; 调节代码文字大小&#xff1a; 按住ctrl滚动滑轮可以调节代码文字大小&#xff1a; ctrl单击打开代码覆盖原标签问题&#xff1a; idea在控制台对不同级别的日志打印不同颜色 &#xff1a; “grep console”插件 点击某一行的时候&#x…

docker-compose --version报错

在部署docker-compose后&#xff0c;查看版本时有如下报错: 解决方法: 解决方法&#xff1a; 直接在release中下载对应的linux发行版【docker-compose-linux-x86_64】 https://github.com/docker/compose/releases/tag/v2.18.1 下载完后将软件上传至 Linux的【/usr/local/bin】…

高忆管理:教你一招短线选股法?

投资者在进行短线买卖时&#xff0c;需求把握一些可行的股票战略&#xff0c;以进步成功率。本文将从商场状况、技能剖析、基本面剖析和资金流向四个视点&#xff0c;教你一招短线选股法。 一、商场状况 在短线买卖中&#xff0c;行情是至关重要的。商场上有“牛市”和“熊市”…

【前端实习生备战秋招】—HTML面试题汇总,建议收藏

【前端实习生备战秋招】—HTML面试题汇总&#xff0c;建议收藏 文章目录 【前端实习生备战秋招】—HTML面试题汇总&#xff0c;建议收藏1. src和href的区别2. 对HTML语义化的理解3. DOCTYPE(⽂档类型) 的作⽤4. script标签中defer和async的区别5. 常⽤的meta标签有哪些6. HTML5…