分享下我整理的Spring框架八股笔记

前言:这是我的八股笔记专栏的第六篇文章,大家在收藏本文章的同时建议订阅我的专栏和关注我,我会不断在专栏更新我整理的八股。笔记整理自javaguide,程序员大彬,CT-NOTES等博客。之所以自己整理笔记是想让知识内容更简洁,条理更清晰。笔记内容较简单,大家可以拿走然后在此基础上自己增删修改。另外,如果大家有面试中遇到了没被此笔记覆盖的知识点,欢迎在此文章下留言,我可以添加上去。

1.Spring

-1.Spring用到了哪些设计模式

Spring框架在其设计和实现中使用了多种设计模式,这些设计模式有助于提高代码的可重用性、灵活性和可维护性。以下是一些在Spring中常用的设计模式:

  1. 工厂模式:Spring通过BeanFactory和ApplicationContext来创建对象,其中BeanFactory就是简单工厂模式的体现。工厂模式隐藏了对象实例化的复杂性,并提供一个统一的方式来获取对象。
  2. 单例模式:在Spring中,默认情况下,bean以单例的形式存在。这意味着对于每个bean定义,Spring容器只会创建一个共享的实例。这样做可以减少系统资源的消耗,并减少垃圾回收器的压力。
  3. 代理模式:Spring的面向切面编程(AOP)功能使用到了JDK的动态代理和CGLIB字节码生成技术。这使得可以在不修改源代码的情况下,为对象添加额外的行为。
  4. 策略模式:例如,Resource接口的不同实现类针对不同的资源文件实现了不同的资源获取策略。策略模式允许在运行时选择算法或操作的具体实现。
  5. 模板方法模式:Spring中的JdbcTemplate、RestTemplate等都是模板方法模式的应用。它们提供了一个操作的框架,而具体的实现步骤则可以由子类来提供,从而实现代码复用和减少重复代码。
  6. 观察者模式:Spring事件驱动模型使用了观察者模式。当某个事件发生时,所有注册为该事件监听者的bean都会收到通知。
  7. 装饰器模式:在Spring中,装饰器模式用于给对象添加额外的功能,这比生成子类更为灵活。
  8. 适配器模式:在Spring MVC中,处理器适配器将不同的控制器适配成统一的Handler接口,使得不同的控制器可以被统一处理。
  9. 责任链模式:在AOP中,责任链模式用于组织多个拦截器,形成一个处理请求的责任链。
  10. 桥接模式:在Spring中,桥接模式可以用来解耦抽象部分和实现部分,例如动态切换不同的数据源。

综上所述,这些设计模式的使用不仅体现了Spring框架的灵活性和扩展性,也使得开发人员能够更加专注于业务逻辑,而不必关心底层的细节实现。

0.Spring的优点/为什么用Spring框架

Spring 是一款开源的轻量级的控制反转(IoC)和面向切面(AOP) 开发框架,可以提高开发人员的开发效率以及系统的可维护性。

1.通过Ioc控制反转和DI依赖注入实现松耦合,能够降低组件之间的耦合度,使得代码更加灵活、易于维护和扩展(Spring就是一个大工厂,可以将所有对象的创建和依赖关系维护都交给spring管理)

2.支持AOP面向切面的编程,把日志、事务管理等从业务逻辑中分离出来,提高了代码的复用性和可维护性。

3.支持声明式事务,可以通过声明式事务来管理数据库操作的事务

4.Spring是非侵入式的。使用Spring的框架不用继承Spring的类和接口,

5.Spring框架拥有庞大的社区支持,提供了丰富的文档、教程等资料,用的人多大家交流问题也更加方便

1.IOC和DI

1.什么是IOC控制反转呢?

IOC-Inversion of Control,即控制反转。IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 外部来管理。

为什么叫控制反转?

  • 控制:指的是对象创建(实例化、管理)的权力
  • 反转:控制权交给外部环境(Spring 框架、IoC 容器)

2.DI依赖注入

(1)什么是依赖注入呢?

在Spring创建对象的过程中,把对象依赖的属性注入到对象中。spring就是通过反射来实现注入的。依赖注入主要有三种方式:注解注入(@Autowired),构造器注入和属性注入

3.IOC和DI的作用

最终目标就是:充分解耦,具体实现靠:

  • 使用IOC容器管理bean(IOC)
  • 在IOC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系.

4.Spring的IOC和DI用了什么设计模式

Spring 的 IoC(控制反转)和 DI(依赖注入)使用了工厂模式、单例模式和代理模式等设计模式。具体如下:

  1. 工厂模式:IoC 容器负责创建对象,当需要创建一个对象时,只需配置好相应的配置文件或注解,无需关心对象的创建过程。IoC 容器就像一个工厂,它根据配置文件或注解来生成和管理对象实例。
  2. 单例模式:在 Spring 框架中,默认情况下,Bean 是单例的,即在整个应用中只有一个实例。这是通过单例模式实现的,确保每个 Bean 的生命周期内只有一个共享的实例。
  3. 代理模式:AOP(面向切面编程)是 Spring 的另一个核心特性,它使用代理模式来实现。通过代理模式,可以在不修改原始类代码的情况下,为对象提供额外的功能,例如事务管理和日志记录。

综上所述,这些设计模式共同工作,使得 Spring 框架能够提供一个高度解耦、易于扩展和维护的应用程序架构。

2.AOP

1.什么是AOP

AOP是面向切面编程,将公共逻辑(事务管理、日志、缓存等)封装成切面,跟业务代码进行分离,抽取公共模块复用,降低耦合。切面就是那些与业务无关,但所有业务模块都会调用的公共逻辑。

具体组成:

1.连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等

  • 在SpringAOP中,理解为方法的执行

2.切入点(Pointcut):匹配连接点的式子

  • 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法
  • 连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点。
  • 切入点定义依托一个不具有实际意义的方法进行,即无参数、无返回值、方法体无实际逻辑,然后在上面加个@PointCut注解。

3.通知(Advice):在切入点处执行的操作,也就是共性功能,是通知类的一个函数

4.通知类:定义通知的类

5.切面(Aspect):描述通知与切入点的对应关系。

2.AOP怎么实现

AOP有两种实现方式:静态代理和动态代理。

静态代理

静态代理:代理类在编译阶段生成,在编译阶段将通知织入Java字节码中,也称编译时增强。AspectJ使用的是静态代理。

缺点:代理对象需要与目标对象实现一样的接口,并且实现接口的方法,会有冗余代码。同时,一旦接口增加方法,目标对象与代理对象都要维护。

动态代理

动态代理:代理类在程序运行时创建,AOP框架不会去修改字节码,而是在内存中临时生成一个代理对象,在运行期间对业务方法进行增强,不会生成新类。

3.Spring的AOP是怎么实现的

SpringAOP是通过动态代理实现的。而SpringAOP使用了两种动态代理,分别是JDK的动态代理,以及CGLib的动态代理

如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK 动态代理,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib动态代理 生成一个被代理对象的子类来作为代理。

4.JDK动态代理和CGLIB动态代理的区别

JDK动态代理

如果目标类实现了接口,Spring AOP会选择使用JDK动态代理目标类。代理类根据目标类实现的接口动态生成,不需要自己编写,生成的动态代理类和目标类都实现相同的接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。

缺点:目标类必须有实现的接口。如果某个类没有实现接口,那么这个类就不能用JDK动态代理。

CGLIB动态代理

通过继承实现。如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library)可以在运行时动态生成类的字节码,动态创建目标类的子类对象,在子类对象中增强目标类。

优点:目标类不需要实现特定的接口,更加灵活。

缺点:CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

5.Spring AOP的相关术语

  • 连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等

    • 在SpringAOP中,理解为方法的执行
  • 切入点(Pointcut):匹配连接点的式子

    • 在SpringAOP中,一个切入点可以描述一个具体方法,也可也匹配多个方法

      • 一个具体的方法:如com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
    • 连接点范围要比切入点范围大,是切入点的方法也一定是连接点,但是是连接点的方法就不一定要被增强,所以可能不是切入点。

  • 通知(Advice):在切入点处执行的操作,也就是共性功能

    • 在SpringAOP中,功能最终以方法的形式呈现
  • 通知类:定义通知的类

  • 切面(Aspect):描述通知与切入点的对应关系。

image.png

Spring通知类型

Spring切面可以应用5种类型的通知:

  1. 前置通知(Before):在目标方法被调用之前调用通知功能;
  2. 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  3. 返回通知(After-returning ):在目标方法成功执行之后调用通知;
  4. 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  5. 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的逻辑。

6.Spring一般是怎么使用AOP(公共日志保存/事务处理)

1.怎么用AOP实现公共日志保存

使用aop中的环绕通知+切点表达式,这个表达式就是要找到要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,比如类信息、方法信息、注解、请求方式等,获取到这些参数以后,保存到ES数据库

2.怎么用AOP实现事务处理

在方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

7.多个切面的执行顺序如何控制?

可以使用@Order 注解直接定义切面顺序

// 值越小优先级越高
@Order
@Component
@Aspect
public class LoggingAspect implements Ordered {

3.Spring事务

1.什么是事务

事务是逻辑上的一组操作,要么都执行,要么都不执行。

2.事务的特性ACID

原子性Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;

一致性Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;

隔离性Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;

持久性Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

3.Spring事务实现方式(声明式和编程式)

Spring事务机制主要包括声明式事务和编程式事务。

  • 编程式事务:通过编程的方式管理事务,这种方式带来了很大的灵活性,但很难维护。
  • 声明式事务:在 XML 配置文件中配置或者直接基于注解(推荐使用) : 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)

4.Spring事务有几种事务传播行为

事务传播行为是为了解决业务层方法之间互相调用的事务问题

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

在TransactionDefinition接口中定义了七个事务传播行为:

这里写图片描述

PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:

使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务是两个独立的事务。一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。

使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。

5.Spring事务隔离级别

Spring定义了一个枚举类:Isolation,里面有5个Spring事务隔离级别

1.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.

2.读未提交ISOLATION_READ_UNCOMMITTED` :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

3.读已提交ISOLATION_READ_COMMITTED`: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

4.可重复读ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

5.可串行化ISOLATION_SERIALIZABLE` : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

6.Spring事务失效场景

1.访问权限问题:如果事务方法的访问权限不是定义成public,这样会导致事务失效,因为spring要求被代理方法必须是public的。

2. 方法用final修饰:如果事务方法用final修饰,将会导致事务失效。因为spring事务底层使用了aop,也就是通过jdk动态代理或者cglib,帮我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法添加事务功能。

3.对象没有被spring管理:使用spring事务的前提是:对象要被spring管理,需要创建bean实例。如果类没有加@Controller、@Service、@Component、@Repository等注解,即该类没有交给spring去管理,那么它的方法也不会生成事务。

4.在代码中捕获异常没有抛出:事务通知只有捉到了目标抛出的异常才能进行后续的回滚处理。如果我们自己捕获了异常处理掉了没有抛出,这种情况下spring事务不会回滚。

5.表不支持事务:如果MySQL使用的存储引擎是myisam,这样的话是不支持事务的。因为myisam存储引擎不支持事务。

7.@Transactional注解,注解在什么时候会失效

@Transactional注解在以下情况下会失效:

  1. 方法内部调用了同类中的另一个非事务方法。因为Spring的事务管理是基于AOP代理实现的,当一个类中的方法调用另一个方法时,实际上是通过代理对象进行调用的。如果被调用的方法没有使用@Transactional注解,那么事务管理将不会生效。

  2. 异常类型不正确。@Transactional注解默认只对RuntimeException类型的异常进行回滚,如果是其他类型的异常,需要指定rollbackFor属性。例如,如果要对Exception类型的异常进行回滚,可以这样写:@Transactional(rollbackFor = Exception.class)。

  3. 数据库引擎不支持事务。如果使用的数据库引擎不支持事务,那么@Transactional注解将无法生效。例如,MySQL的MyISAM存储引擎就不支持事务。

  4. 多数据源配置错误。在使用多数据源的情况下,如果不同数据源之间的事务管理没有正确配置,那么@Transactional注解可能会失效。需要确保每个数据源都有对应的事务管理器和事务通知器。

  5. 事务传播行为设置不当。@Transactional注解有一个propagation属性,用于设置事务的传播行为。如果不正确地设置了传播行为,可能会导致事务失效。例如,如果设置为Propagation.REQUIRES_NEW,那么每次调用都会创建一个新的事务,而不是加入到当前事务中。

4.bean

0.Sping 的bean为什么用到了单例模式?

Spring中的Bean默认使用单例模式,以下是几个可能的原因:

  • 节省资源:单例模式确保一个类只有一个实例,这样可以减少系统资源的消耗,特别是当一个对象的创建和销毁需要较大成本时,如数据库连接或大型配置对象。
  • 共享状态:单例模式允许多个对象共享一个实例的状态,这在需要共享数据或维持特定状态的场景中非常有用。
  • 性能提升:由于不需要频繁地创建和销毁对象,单例模式可以提高应用程序的性能。
  • 容器管理:Spring容器负责管理单例Bean的生命周期,包括创建、初始化、装配和其他生命周期回调,这有助于简化Bean的管理和维护。

综上所述,Spring中的Bean使用单例模式主要是为了节省资源、共享状态、提高性能以及方便容器管理。这些因素共同作用,使得单例模式成为Spring Bean的默认选择。当然,如果需要,开发者也可以将Bean定义为原型模式,以便每次请求都创建一个新的实例。

1.什么是bean

Bean 代指的就是那些被 IoC 容器所管理的对象。

我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。

2.将一个类声明为 Bean 的注解有哪些?

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

3.@Component 和 @Bean 的区别是什么?

都是使用注解定义 Bean。@Bean 是使用 Java 代码装配 Bean,@Component 是自动装配 Bean。

@Component 注解用在类上,表明一个类会作为组件类,并告知Spring要为这个类创建bean,每个类对应一个 Bean。

@Bean 注解用在方法上,表示这个方法会返回一个 Bean。@Bean 需要在配置类中使用,即类上需要加上@Configuration注解。

当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

4.Bean 的作用域/作用范围有哪些?

Spring 中 Bean 的作用域通常有下面几种:

  • singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
  • prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
  • request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
  • session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
  • application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
  • websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。

5.bean是线程安全的吗

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

prototype 作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。singleton 作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题,这取决于 Bean 是否有状态(就是说这个bean是否是包含可变的成员变量的对象)。如果这个 bean 是有状态的话,那就存在线程安全问题(**有状态 Bean 是指)。

不过,大部分 Bean 实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

单例bean线程安全问题解决办法

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

  1. 在 Bean 中尽量避免定义可变的成员变量。
  2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

5.SpringBoot如何实现自动装配?

SpringBoot通过**@EnableAutoConfiguration注解和自动配置类**实现自动装配。

SpringBoot的自动装配机制主要涉及以下几个步骤:

  1. 使用@SpringBootConfiguration注解:该注解中包含@EnableAutoConfiguration,它是实现自动装配的起始点。
  2. 启用自动配置:通过@EnableAutoConfiguration注解启用自动配置功能,该注解会导入一个特殊的组件,即AutoConfigurationImportSelector类型的组件。
  3. 加载自动配置类:AutoConfigurationImportSelector类型的组件会根据项目的依赖以及spring.factories文件中的配置,自动导入相应的自动配置类到Spring容器中。
  4. 按需加载配置类:所有被扫描到的自动配置类将根据条件进行生效,比如对应的配置文件是否存在,依赖是否满足等。满足条件的自动配置类将会为容器装配所需的组件。
  5. 自定义配置:如果需要替换或修改默认的自动配置,可以通过定义自己的@Bean来替换默认的Bean,或者在application.properties中修改相关参数来达到定制化配置的目的。
  6. SPI机制:SpringBoot还采用了Service Provider Interface (SPI)机制来实现一些自动装配的功能,使得程序可以自动地、可插拔地进行装配。

综上所述,SpringBoot的自动装配大大简化了项目的配置工作,允许开发者更专注于业务代码的编写,而无需过多关心底层的配置细节。不过,理解其背后的原理有助于更好地掌控SpringBoot应用的配置和开发。

6.bean自动装配的方式/注入方式有哪些?

Spring的自动装配有三种模式:byType(根据类型),byName(根据名称)、constructor(根据构造函数)。

byType

找到与依赖类型相同的bean注入到另外的bean中,这个过程需要借助setter注入来完成,因此必须存在set方法,否则注入失败。

默认情况下@Autowired是按类型匹配的(byType)。如果需要按名称(byName)匹配的话,可以使用@Qualifier注解与@Autowired结合。

当需要创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个 bean 来消除歧义。

byName

将属性名与bean名称进行匹配,如果找到则注入依赖bean。

constructor

无论名称是否匹配,存在单个实例则优先按类型进行参数匹配,当存在多个类型相同实例时,按名称优先匹配,如果没有找到对应名称,则注入失败。

7.bean的生命周期

1.调用bean的构造方法创建Bean

2.通过反射调用setter方法进行属性的依赖注入

3.如果Bean实现了BeanNameAware接口,Spring将调用setBeanName(),设置 Bean的name(xml文件中bean标签的id)

4.如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()把bean factory设置给Bean

5.如果存在BeanPostProcessor,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法,在Bean初始化前对其进行处理

6.如果Bean实现了InitializingBean接口,Spring将调用它的afterPropertiesSet方法,然后调用xml定义的 init-method 方法,两个方法作用类似,都是在初始化 bean 的时候执行

7.如果存在BeanPostProcessor,Spring将调用它们的postProcessAfterInitialization(后初始化)方法,在Bean初始化后对其进行处理

8.Bean初始化完成,供应用使用,这里分两种情况:

8.1 如果Bean为单例的话,那么容器会返回Bean给用户,并存入缓存池。如果Bean实现了DisposableBean接口,Spring将调用它的destory方法,然后调用在xml中定义的 destory-method方法,这两个方法作用类似,都是在Bean实例销毁前执行。

8.2 如果Bean是多例的话,容器将Bean返回给用户,剩下的生命周期由用户控制。

8.BeanFactory和FactoryBean的区别?

BeanFactory:是所有Spring Bean的容器根接口,给Spring 的容器定义一套规范,给IOC容器提供了一套完整的规范,比如我们常用到的getBean方法等

FactoryBean:是一个bean。但是他不是一个普通的bean,是可以创建对象的bean。。通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,直接用xml配置比较麻烦,这时可以考虑用FactoryBean,可以隐藏实例化复杂Bean的具体的细节.

9.BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

两者区别如下:

1、功能上的区别。BeanFactory是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。

ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能,如继承MessageSource、支持国际化、统一的资源文件访问方式、同时加载多个配置文件等功能。

2、加载方式的区别。BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

而ApplicationContext是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单例Bean,那么在需要的时候,不需要等待创建bean,因为它们已经创建好了。

相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

10.怎么让2个bean按顺序加载?

当一个 bean 需要在另一个 bean 初始化之后再初始化时,可以使用@DependOn注解

11.spring的bean是否会被jvm的gc回收

Spring的单例(singleton)bean在Spring容器运行期间通常不会被JVM的垃圾回收器(GC)回收,而原型(prototype)bean则可能在不再被引用时被回收。具体如下:

  1. 单例(Singleton)Beans:默认情况下,Spring容器中创建的bean是单例的,即在整个应用程序生命周期内只存在一个实例。这些单例bean通常与Spring容器具有相同的生命周期,除非Spring容器被关闭或bean被显式销毁,否则它们会一直存在于内存中,因此不会被JVM的GC回收。
  2. 原型(Prototype)Beans:与单例bean不同,原型bean每次请求时都会创建一个新的实例。这意味着它们的生命周期通常较短,使用完毕后如果没有其他引用指向它们,就可能会被JVM的GC回收。
  3. 作用域和生命周期:Spring bean的作用域和生命周期也会影响其是否被回收。例如,如果一个bean被配置为在某个特定的生命周期结束或某个条件满足时销毁,那么它将可能被JVM回收。
  4. 弱引用和软引用:如果在Spring配置中使用了弱引用或软引用,那么即使bean仍然在Spring容器中,也可能在JVM的下一次GC周期中被回收,因为弱引用和软引用的对象更容易被GC处理。
  5. Spring容器关闭:当Spring容器关闭时,所有的单例bean都会被销毁,此时它们将变得不可达,从而可能被JVM的GC回收。

综上所述,Spring的bean是否会被JVM的GC回收取决于其作用域、生命周期以及Spring容器的状态。单例bean在Spring容器运行期间通常不会被回收,而原型bean和其他特定条件下的bean可能会被回收。

12.springboot中不想加载一个bean如何做

要在Spring Boot中阻止一个bean被加载,您可以采取以下几种方法:

  1. 自定义@ComponentScan:通过自定义@ComponentScan注解,您可以指定需要扫描的包路径,从而排除不想加载的bean。在@ComponentScan注解中使用excludeFilters属性来排除特定的类。
  2. 使用@SpringBootApplication的exclude属性:如果您使用的是@SpringBootApplication注解,可以利用它的exclude属性来排除自动配置类。例如,如果您不想加载某个自动配置类,可以在@SpringBootApplication注解中列出这个类。
  3. 使用@EnableAutoConfiguration的exclude属性:在Spring Boot的启动类上使用@EnableAutoConfiguration(exclude = {ClassNotToLoad.class}),这样可以排除掉不需要自动配置的类。
  4. 使用TypeExcludeFilter:创建一个自定义的TypeExcludeFilter实现,并在@ComponentScan注解中引用它。这样可以实现更精细的控制,只排除特定类型的bean。
  5. 移除相关注解:如果某个bean是通过@Component、@Service、@Repository等注解自动注册到Spring容器中的,您可以通过移除这些注解来阻止它的加载。
  6. 调整bean加载顺序:在某些情况下,您可能需要控制bean的加载顺序。虽然@Order、@AutoConfigureOrder、@AutoConfigureAfter和@AutoConfigureBefore等注解主要用于控制Spring组件的顺序,但它们也可以在一定程度上影响bean的加载顺序。

总的来说,您可以通过上述方法来控制Spring Boot项目中哪些bean被加载,哪些不被加载。这些方法可以帮助您更好地管理Spring容器中的bean,确保只有需要的bean被实例化和使用。

5.Spring循环依赖问题(三级缓存)

循环依赖其实就是循环引用,也就是两个或两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A。

首先,有两种Bean注入的方式。

构造器注入和属性注入。

就有了2种循环依赖。

对于构造器注入的循环依赖,Spring处理不了,会直接抛出异常。我们可以使用@Lazy懒加载,什么时候需要对象再进行bean对象的创建

对于属性注入的循环依赖,是通过三级缓存处理来循环依赖的。

1.singletonObjects:一级缓存,里面放置的是已经完成所有创建动作的单例对象,也就是说这里存放的bean已经完成了所有创建的生命周期过程,在项目运行阶段当执行多次getBean()时就是从一级缓存中获取的。 2.earlySingletonObjects:二级缓存,里面存放的只是进行了实例化的bean,还没有进行属性设置和初始化操作,也就是bean的创建还没有完成,还在进行中,这里是为了方便被别的bean引用 3.singletonFactories:三级缓存,Spring中的每个bean创建都有自己专属的ObjectFactory工厂类,三级缓存缓存的就是对应的bean的工厂实例,可以通过该工厂实例的getObject()方法获取该bean的实例。

下面我来讲一下通过三级缓存处理来循环依赖的过程吧。

第一,先实例A对象,同时会创建ObjectFactory对象存入三级缓存singletonFactories

第二,A在初始化的时候需要B对象,这个走B的创建的逻辑

第三,B实例化完成,也会创建ObjectFactory对象存入三级缓存singletonFactories

第四,B需要注入A,通过三级缓存中获取ObjectFactory来生成一个A的对象同时存入二级缓存,这个是有两种情况,一个是可能是A的普通对象,另外一个是A的代理对象,都可以让ObjectFactory来生产对应的对象,这也是三级缓存的关键

第五,B通过从通过二级缓存earlySingletonObjects 获得到A的对象后可以正常注入,B创建成功,存入一级缓存singletonObjects

第六,回到A对象初始化,因为B对象已经创建完成,则可以直接注入B,A创建成功存入一次缓存singletonObjects

第七,二级缓存中的临时对象A清除

为什么要有第三级缓存?

如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象

6.Spring启动过程

  1. 读取web.xml文件。
  2. 创建 ServletContext,为 ioc 容器提供宿主环境。
  3. 触发容器初始化事件,调用 contextLoaderListener.contextInitialized()方法,在这个方法会初始化一个应用上下文WebApplicationContext,即 Spring 的 ioc 容器。ioc 容器初始化完成之后,会被存储到 ServletContext 中。
  4. 初始化web.xml中配置的Servlet。如DispatcherServlet,用于匹配、处理每个servlet请求。

7.Spring 框架中用到了哪些设计模式?

关于下面这些设计模式的详细介绍,可以看我写的 Spring 中的设计模式详解open in new window 这篇文章。

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

2.Spring MVC

1.什么是Spring MVC

SpringMVC是一种基于 Java 的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于Spring框架的一个模块。

它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful编程风格的请求。

2.什么是MVC模式

MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。

MVC设计模式是一种软件架构模式,它通过将应用程序分为三个核心组件来组织代码,以实现业务逻辑、数据和界面显示的分离。这三个组件分别是:

  1. 模型(Model):模型代表应用程序的数据结构和业务逻辑,它负责处理应用程序的数据和业务规则。模型可以直接管理数据库,并且当数据发生变化时,它能够通知视图进行更新。
  2. 视图(View):视图是用户界面的组成部分,它负责展示模型中的数据。视图通常会从模型中获取数据并显示给用户,但它并不直接与模型交互,而是通过控制器来进行数据的更新和请求。
  3. 控制器(Controller):控制器作为模型和视图之间的中介,它负责接收用户的输入,并根据输入更新模型或视图。控制器处理用户的请求,决定调用哪个模型来处理数据,并选择相应的视图来显示响应。

MVC设计模式的目的是提高代码的复用性和灵活性,使得开发人员可以独立地修改视图或业务逻辑而不影响其他部分。这种分离还简化了测试过程,因为每个组件都可以单独进行测试。

总之,理解MVC设计模式的关键在于认识到其将应用程序的不同关注点分离开来,每个组件都有其明确的职责,相互之间通过定义良好的接口进行通信。这种设计模式在现代软件开发中非常常见,尤其是在构建复杂的桌面、Web和企业级应用程序时。

3.什么是拦截器

1.什么是拦截器

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  • 作用:
    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行

2.怎么自定义拦截器

Spring MVC 拦截器对应HandlerInterceor接口,该接口位于org.springframework.web.servlet的包中,定义了三个方法,若要实现该接口,就要实现其三个方法:

  1. 前置处理(preHandle()方法):该方法在执行控制器方法之前执行。返回值为Boolean类型,如果返回false,表示拦截请求,不再向下执行,如果返回true,表示放行,程序继续向下执行(如果后面没有其他Interceptor,就会执行controller方法)。所以此方法可对请求进行判断,决定程序是否继续执行,或者进行一些初始化操作及对请求进行预处理。
  2. 后置处理(postHandle()方法):该方法在执行控制器方法调用之后,且在返回ModelAndView之前执行。由于该方法会在DispatcherServlet进行返回视图渲染之前被调用,所以此方法多被用于处理返回的视图,可通过此方法对请求域中的模型和视图做进一步的修改。
  3. 已完成处理(afterCompletion()方法):该方法在执行完控制器之后执行,由于是在Controller方法执行完毕后执行该方法,所以该方法适合进行一些资源清理,记录日志信息等处理操作。

3.拦截器工作流程

1.所有的拦截器(Interceptor)和处理器(Handler)都注册在HandlerMapping中。

2.Spring MVC中所有的请求都是由DispatcherServlet`分发的。

3.当请求进入DispatcherServlet.doDispatch()时候,首先会得到处理该请求的Handler(即Controller中对应的方法)以及所有拦截该请求的拦截器。拦截器就是在这里被调用开始工作的。

4.当有拦截器后,请求会先进入preHandle方法,如果方法返回true,postHandleafterCompletion才有可能被执行。如果返回false,则直接跳过后面方法的执行。

4.拦截器和过滤器的区别

  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
  • 拦截器提供了三个方法,分别在不同的时机执行;过滤器仅提供一个方法

4.什么是restful风格

RESTful风格是一种软件架构风格,使用统一的资源标识符(URI)来表示资源、使用标准的HTTP方法(如GET、POST、PUT、DELETE)来对资源进行操作、使用状态码来表示操作结果等.

GET代表获取一个资源,POST代表添加一个资源,PUT代表修改一个资源,DELETE代表删除一个资源

常用的RESTful状态码包括:

常见 HTTP 状态码

  1. 200 OK:表示请求成功。
  2. 201 Created:表示新资源已经成功创建。
  3. 204 No Content:表示服务器成功处理了请求,但没有返回任何内容。
  4. 400 Bad Request:表示请求无效,例如缺少必需的参数。
  5. 401 Unauthorized:表示未经授权,需要进行身份验证。
  6. 403 Forbidden:表示服务器理解请求,但拒绝执行。
  7. 404 Not Found:表示请求的资源不存在。
  8. 405 Method Not Allowed:表示请求中指定的方法不被允许。
  9. 500 Internal Server Error:表示服务器遇到了一个未曾预料的状况,导致无法完成对请求的处理。

5.SpringMVC执行流程/工作原理

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

6.Spring MVC的主要组件?

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

7.Spring MVC的异常处理

三种方法:

  • 使用系统定义好的异常处理器 SimpleMappingExceptionResolver
  • 使用自定义异常处理器
  • 使用异常处理注解(@ControllerAdvice + @ExceptionHandler)

3.Springboot

0.Javaweb、spring、springmvc和springboot有什么区别,都是做什么用的?

JavaWeb是 Java 语言的 Web 开发技术,主要用于开发 Web 应用程序,包括基于浏览器的客户端和基于服务器的 Web 服务器。

Spring是一个轻量级的开源开发框架,主要用于管理 Java 应用程序中的组件和对象,并提供各种服务,如事务管理、安全控制、面向切面编程和远程访问等。它是一个综合性框架,可应用于所有类型的 Java 应用程序。

SpringMVC是 Spring 框架中的一个模块,用于开发 Web 应用程序并实现 MVC(模型-视图-控制器)设计模式,它将请求和响应分离,从而使得应用程序更加模块化、可扩展和易于维护。

Spring Boot是基于 Spring 框架开发的用于开发 Web 应用程序的框架,它帮助开发人员快速搭建和配置一个独立的、可执行的、基于 Spring 的应用程序,从而减少了繁琐和重复的配置工作。

综上所述,JavaWeb是基于 Java 语言的 Web 开发技术,而 Spring 是一个综合性的开发框架,SpringMVC用于开发 Web 应用程序实现 MVC 设计模式,而 Spring Boot 是基于 Spring 的 Web 应用程序开发框架。

1.Spring Boot 的核心注解是哪个?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

  • @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。
  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。
  • @ComponentScan:Spring组件扫描。

2.Springboot自动配置原理

在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

其中@EnableAutoConfiguration是实现自动化配置的核心注解。

该注解通过@Import注解导入对应的配置选择器。关键的是内部就是读取了该项目和该项目引用的Jar包的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。

在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。

一般条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。

3.Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?

  • Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar 命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类。
  • Spring Boot 的 jar 无法被其他项目依赖,主要还是他和普通 jar 的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes 目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用。

4.springboot 默认的包扫描路径?

SpringBoot默认的包扫描路径是启动类所在的包及其子包

在SpringBoot中,默认情况下,框架会自动扫描启动类所在包下的所有Java类,以便发现并注册Spring组件,如@Service、@Repository、@Controller等。这种自动扫描机制简化了配置过程,使得开发者无需手动指定每个组件的扫描路径。

5.springboot的启动类的注解@SpringbootApplication工作原理:

@SpringBootApplication是Spring Boot的核心注解,它主要包含以下三个注解:

  1. @SpringBootConfiguration:表示这是一个Spring Boot的配置类。
  2. @EnableAutoConfiguration:让Spring Boot根据项目中的依赖自动配置相关的bean。
  3. @ComponentScan:告诉Spring Boot扫描哪些包下的类作为组件(component)。

工作原理如下:

  1. 当Spring Boot应用启动时,会扫描主程序类上的@SpringBootApplication注解。
  2. 根据@SpringBootConfiguration注解,将当前类作为配置类。
  3. 根据@ComponentScan注解,扫描指定包下的类,并将其注册为Spring容器中的Bean。
  4. 根据@EnableAutoConfiguration注解,Spring Boot会自动根据项目中的依赖配置相关的Bean。例如,如果项目中引入了spring-boot-starter-web依赖,那么Spring Boot会自动配置Tomcat和Spring MVC等相关的Bean。
  5. Spring Boot会将所有配置好的Bean注入到Spring容器中,完成自动配置。
  6. 最后,Spring Boot会调用主程序类的main方法,启动应用。

6.spring boot应用启动慢怎么优化启动时间?

要优化Spring Boot应用的启动时间,可以采取以下几种方法:

  1. 减少业务初始化:检查并减少应用中的初始化逻辑,尤其是那些耗时的操作,如建立数据库连接、Redis连接和其他各种连接池。尽量减少不必要的依赖,能够异步处理的就异步处理。
  2. 使用Spring Boot 2.2及以上版本的新特性:Spring Boot 2.2版本引入了spring.main.lazy-initialization属性,将其配置为true可以实现所有Bean的延迟初始化,这样可以在一定程度上提高启动速度。但需要注意的是,这样可能会导致第一次访问时响应较慢。
  3. 并行化:考虑将一些初始化流程并行化,比如使用多线程或异步任务来同时处理多个初始化操作。
  4. 优化依赖管理:确保项目中的依赖是最优的,避免引入不必要的库和框架。同时,可以使用Maven或Gradle的懒加载特性,只在需要时才加载某些依赖。
  5. 特定于配置文件的配置:根据不同的环境(开发、测试、生产)选择合适的配置,以减少不必要的资源消耗和初始化操作。
  6. 分析并优化代码执行路径:使用性能分析工具(如VisualVM、JProfiler等)来监控应用启动过程中的资源消耗和瓶颈,针对性地进行优化。
  7. 优化日志系统:如果应用在启动时加载了大量的日志配置,可以考虑简化日志系统,或者延迟加载日志配置文件。
  8. 数据库优化:如果应用启动时需要加载大量的数据,可以考虑优化数据库查询,或者将数据加载操作移到后台线程中进行。
  9. 资源文件优化:对于资源文件(如图片、模板等),可以考虑使用懒加载或者CDN服务,以减少应用启动时的加载压力。
  10. 硬件资源:确保服务器硬件资源充足,如内存、CPU等,以支持应用快速启动。
  11. 容器优化:如果应用部署在容器中,可以考虑优化容器的启动参数和资源配置。
  12. 外部服务调用:如果应用启动时需要调用外部服务,可以考虑将这些调用延迟到应用启动后进行,或者使用缓存来存储这些服务的返回结果。
  13. 代码质量:提高代码质量,避免复杂的构造函数和大量的单例模式,这些都可能导致应用启动变慢。
  14. 监控和日志:启用详细的启动日志,监控应用启动过程中的各个阶段,以便于找到具体的瓶颈所在。
  15. 第三方库和服务:检查并优化第三方库和服务的使用,有些库可能在启动时执行了大量操作,可以考虑替换或者升级这些库。
  16. JVM参数调优:根据实际情况调整JVM参数,如增加初始堆大小、优化垃圾回收策略等,以提高应用启动效率。
  17. 分布式配置中心:如果使用了分布式配置中心,可以考虑在启动时只加载必要的配置,其他配置可以按需加载。
  18. 预热应用:在生产环境中,可以通过预热应用的方式,提前加载一些资源和数据,以减少实际用户使用时的启动时间。
  19. 自动化测试:通过自动化测试来持续监控和优化应用的启动时间,确保每次变更都能满足性能要求。

总之,通过上述方法,您可以有效地优化Spring Boot应用的启动时间,提高用户体验和应用的可用性。在实施这些优化措施时,请根据实际情况和具体需求进行选择和调整。

4.Spring框架常用注解

1.Spring常用注解

第一类是:声明bean,有@Component、@Service、@Repository、@Controller

第二类是:依赖注入相关的,有@Autowired、@Qualifier、@Resourse

第三类是:设置作用域 @Scope

第四类是:spring配置相关的,比如@Configuration,@ComponentScan 和 @Bean

第五类是:跟aop相关做增强的注解 @Aspect,@Before,@After,@Around,@Pointcut

1.@Component、@Controller、@Repositor和@Service 的区别?

@Component:表明一个类会作为组件类,并告知Spring要为这个类创建bean。

@Controller:将类标记为 Spring Web MVC 控制器。

@Service:将类标记为业务层组件。

@Repository:将类标记为数据访问组件,即DAO组件。

2.@Bean和@Component有什么区别?

都是使用注解定义 Bean。

1.@Bean 是使用 Java 代码装配 Bean,@Component 是自动装配 Bean。

2.@Component 注解用在类上,表明一个类会作为组件类,并告知Spring要为这个类创建bean,每个类对应一个 Bean。@Bean 注解用在方法上,表示这个方法会返回一个 Bean。@Bean 需要在配置类中使用,即类上需要加上@Configuration注解。

3.当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

3.@Qualifier 注解有什么作用

默认情况下@Autowired是按类型匹配的(byType)。如果需要按名称(byName)匹配的话,可以使用@Qualifier注解与@Autowired结合。

当一个接口存在多个实现类且它们都已经被 Spring 容器所管理的话,这时候就会有多个同类型的bean,根据类型注入这种方式就无法正确注入对象了,因为这个时候 Spring 会同时找到多个满足条件的选择,默认情况下它自己不知道选择哪一个。

可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个 bean 来消除歧义。

4.注入bean的2个注解@Autowired和@Resource的区别?

1.@Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

2.Autowired 默认的注入方式为byType(根据类型进行匹配。

@Resource 有两个比较重要且日常开发常用的属性:name(名称)、type(类型)。如果仅指定 name 属性则注入方式为byName,如果仅指定type属性则注入方式为byType

3.当存在多个同类型的bean(比如一个接口有两个实现类,且它们都已经被 Spring 容器所管理。),@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来指定名称,@Resource可以通过 name 属性来指定名称。

2.Spring MVC常见注解

  • @Controller:用于标识此类的实例是一个控制器。
  • @RequestMapping:映射Web请求(访问路径和参数)。
  • @ResponseBody:注解返回数据而不是返回页面
  • @RequestBody:注解实现接收 http 请求的 json 数据,将 json 数据转换为 java 对象。
  • @PathVariable:用于接收路径参数,使用{参数名称}描述路径参数
  • @RequestParam:用于接收url地址传参或表单传参
  • @RestController:@Controller+@ResponseBody
  • @ExceptionHandler标识一个方法为全局异常处理的方法。

1.@Controller 注解有什么用?

@Controller 注解标记一个类为 Spring Web MVC 控制器。Spring MVC 会将扫描到该注解的类,然后扫描这个类下面带有 @RequestMapping 注解的方法,根据注解信息,为这个方法生成一个对应的处理器对象.

2.@RequestMapping 注解有什么用?

@RequestMapping 注解,用于配置处理器的 HTTP 请求方法,URI等信息,这样才能将请求和方法进行映射。这个注解可以作用于类上面,也可以作用于方法上面,在类上面一般是配置这个控制器的 URI 前缀。

3.@RestController 和 @Controller 有什么区别?

@RestController 注解,在 @Controller 基础上,增加了 @ResponseBody 注解,更加适合目前前后端分离的架构下,提供 Restful API ,返回 JSON 数据格式。

4.@RequestMapping 和 @GetMapping 注解有什么不同?

  1. @RequestMapping:可注解在类和方法上;@GetMapping 仅可注册在方法上
  2. @RequestMapping:可进行 GET、POST、PUT、DELETE 等请求方法;@GetMapping@RequestMapping 的 GET 请求方法的特例。

5.@RequestParam 和 @PathVariable 两个注解的区别

@PathVariable主要用于接收http://host:port/path/{参数值}数据。@RequestParam主要用于接收http://host:port/path?参数名=参数值数据,这里后面也可以不跟参数值。

@RequestParam和@PathVariable这两者之间区别不大,主要是请求的URL不一样

用@RequestParam请求接口时,URL是:http://www.test.com/user/getUserById?userId=1

用@PathVariable请求接口时,URL是:http://www.test.com/user/getUserById/2

3.Springboot常见注解-@SpringBootApplication

Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 :

  • @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能;
  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项
  • @ComponentScan:Spring组件扫描

@SpringBootApplication注解工作流程

以下是Spring Boot启动类注解的工作流程:

  1. 初始化SpringApplication:在Spring Boot应用启动时,首先会进行SpringApplication的初始化。这个过程包括设置源(即设置Spring容器启动时依赖的初始配置类),设置WEB应用程序类型(例如SERVLET或REACTIVE),以及配置一些基本的环境变量、资源、构造器和监听器。
  2. 加载配置环境:在初始化之后,Spring Boot会根据项目的配置(如application.properties或application.yml文件)加载配置环境。这些配置信息将被用来设置Spring应用的各种参数,如数据库连接、服务器端口等。
  3. 创建上下文环境:接着,Spring Boot会创建应用上下文环境。在这个过程中,Spring Boot会根据项目中定义的Beans和自动配置项来构建Spring容器。
  4. 自动化配置:Spring Boot的一个核心特性是自动化配置,它会根据项目的依赖和配置自动配置Spring应用。例如,如果项目中包含了spring-boot-starter-web依赖,Spring Boot会自动配置嵌入式的Tomcat服务器和Spring MVC相关的组件。
  5. 启动应用:最后,通过调用SpringApplication.run(SpringBoot.class, args)方法,Spring Boot会启动内嵌的Web服务器(默认为Tomcat),并开始监听指定的端口,等待接收请求。

5.MyBatis

0.Mybatis和Mybatis-plus的区别

MyBatis和MyBatis-Plus在实现方式、功能支持以及编程风格方面存在一些差异。具体分析如下:

  1. 实现方式:MyBatis是基于XML或注解方式进行数据库操作的持久化框架,提供了基本的CRUD操作及动态SQL生成等功能。MyBatis-Plus则是在MyBatis的基础上进行了扩展和增强,通过提供更加简化的API使得开发更为便捷,同时在性能、效率和易用性上都有所优化。
  2. 功能支持:MyBatis-Plus相较于MyBatis增加了许多额外的实用组件,例如条件构造器、代码生成器、分页插件和性能分析拦截器等,这些工具可以大幅减少开发者编写SQL语句的工作量并提升开发效率。而MyBatis则相对原始,需要手动编写大量SQL语句来实现复杂功能。
  3. 编程风格:在MyBatis中,通常需要定义mapper.xml文件和使用相应的SQL查询语句,而在MyBatis-Plus中,开发者可以通过继承BaseMapper和使用Lambda表达式,以一种更接近于声明式编程的方式来进行数据库操作。这种方式类似于Spring Data JPA,极大地简化了数据访问层的代码。

总的来说,Mybatis-Plus是在Mybatis基础上的一个增强工具,它兼容所有Mybatis原生特性,引入Mybatis-Plus不会对现有的Mybatis构架产生影响。如果项目追求更高的开发效率和便利性,可以选择Mybatis-Plus;如果需要更多的灵活性和控制性,或者对自动生成的代码有顾虑,那么使用Mybatis可能更合适。

1.Mybatis是什么?

  • MyBatis框架是一个开源的数据持久层框架。
  • 它的内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询、存储过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设置以及结果集的检索。
  • MyBatis作为持久层框架,其主要思想是将程序中的大量SQL语句剥离出来,配置在配置文件当中,实现SQL的灵活配置。
  • 这样做的好处是将SQL与程序代码分离,可以在不修改代码的情况下,直接在配置文件当中修改SQL。

2.Mybatis分页方式以及是怎么分页的

MyBatis分页一般可以分为如下两类。 1)逻辑分页,先查询出所有的数据并缓存到内存,再根据业务相关需求,从内存数据中筛选出合适的数据进行分页。 2)物理分页,直接利用数据库支持的分页语法来实现,比如 MySQL 中提供了分页关键词Limit。

MyBatis 提供的4种分页方式 1)在MyBatis Mapper 配置文件中直接写分页 SQL,这种方式比较灵活,实现也简单

2)RowBounds 实现逻辑分页,也就是一次性加载所有符合查询条件的目标数据,根据页参数值在内存中实现分页。当然,在数据量比较大的情况下,JDBC 驱动本身会做一些优化也就是说,不会把所有结果存储在 ResultSet 中,而是只加载一部分数据,再根据需求从数据库中加载。这种方式不适合数据量较大的场景,而且有可能会因频繁访问数据库造成比较大的压力o

3)Interceptor 拦截器实现,通过拦截需要分页的 select 语句,并在这个 select 语句中动态拼接分页关键字,从而实现分页查询,Interceptor 是 MyBatis 提供的一种针对不同生命周期的拦截器,比如拦截执行器方法、拦截参数的处理、拦截结果集的处理、拦截 SQL 语法构建的处理。我们可以通过拦截不同阶段的处理来实现 MyBatis 相关功能的扩展。采用这种方式的好处就是,可以提供统一的处理机制,不需要我们单独维护分页相关的功能

4)插件(PageHelper)及(MyBaits-Plus、tkmybatis)框架实现,这些插件本质上也是使用Mybatis 的拦截器来实现的。它们帮我们实现了扩展和封装,节省了分页扩展封装的工作量,在实际开发中拿来即用即可。

3.MyBatis执行流程/工作原理

①读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件

②构造会话工厂SqlSessionFactory,一个项目只需要一个,单例的,一般由spring进行管理

③会话工厂创建SqlSession对象,这里面就含了执行SQL语句的所有方法

④操作数据库的接口,Executor执行器,同时负责查询缓存的维护

⑤Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息

⑥输入参数映射

⑦输出结果映射

4.MyBatis延迟加载

1.Mybatis是否支持延迟加载?

延迟加载的意思是:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。

Mybatis支持一对一关联对象和一对多关联集合对象的延迟加载

在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false,默认是关闭的

2.延迟加载的底层原理知道吗?

延迟加载的基本原理是,使用 CGLIB 动态代理创建目标对象的代理对象,当调用目标方法时,进入拦截器方法。

比如调用a.getB().getName(),拦截器 invoke()方法发现 a.getB()是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用a.setB(b),于是 a 的对象 b 属性就有值了,接着完成a.getB().getName()方法的调用。

5.Mybatis的一级,二级缓存

Mybatis里面设计了二级缓存来提升数据的检索效率,避免每次数据的访问都需要去查询数据库。

一级缓存是SqlSession级别的缓存:Mybatis对缓存提供支持,默认情况下只开启一级缓存,一级缓存作用范围为同一个SqlSession。在SQL和参数相同的情况下,我们使用同一个SqlSession对象调用同一个Mapper方法,往往只会执行一次SQL。因为在使用SqlSession第一次查询后,Mybatis会将结果放到缓存中,以后再次查询时,如果没有声明需要刷新,并且缓存没超时的情况下,SqlSession只会取出当前缓存的数据,不会再次发送SQL到数据库。若使用不同的SqlSession,因为不同的SqlSession是相互隔离的,不会使用一级缓存。

二级缓存需要自己开启:可以使缓存在各个SqlSession之间共享。当多个用户在查询数据的时候,只要有任何一个SqlSession拿到了数据就会放入到二级缓存里面,其他的SqlSession就可以从二级缓存加载数据。

Mybatis的二级缓存什么时候会清理缓存中的数据?

当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear。

#八股##腾讯##美团##王者农药##字节#
Java抽象带蓝子的笔记专栏 文章被收录于专栏

我的笔记专栏,内有自己整理的八股知识笔记和算法刷题笔记,我会不断通过他人和自己的面经来更新和完善自己的八股笔记。专栏每增加一篇文章费用就会上涨一点,如果你喜欢的话建议你尽早订阅。

全部评论
终于等到spring了篮子哥,就好这一口看别的咳嗽
点赞
送花
回复
分享
发布于 05-06 18:48 上海
太好看啦!!!!
点赞
送花
回复
分享
发布于 05-15 04:01 海南
滴滴
校招火热招聘中
官网直投

相关推荐

16 75 评论
分享
牛客网
牛客企业服务