1 什么是Spring框架
Spring框架是一个开源的Java应用程序开发框架,它提供了很多工具和功能,可以帮助开发者更快地构建企业级应用程序。通过使用Spring框架,开发者可以更加轻松地开发Java应用程序,并且可以更加灵活地组织和管理应用程序中的对象和组件。
Spring框架的核心思想是控制反战(IOC)、依赖注入(DI)和面向切面编程(AOP)。控制反转(IOC)是将实例的控制权交给外部容器,统一管理。依赖注入(DI)可以帮助我们更好地组织和管理应用程序中的对象,使得应用程序更加松耦合,易于扩展和维护。面向切面编程(AOP)可以帮助我们更好地管理应用程序中的横切关注点,比如日志、事务、安全等,使得应用程序更加模块化和可维护。
除了核心容器以外,Spring框架还提供了很多其他的组件和框架,比如Spring MVC可以帮助我们更加轻松地开发Web应用程序,Spring JDBC可以帮助我们更加轻松地访问和操作数据库,Spring ORM可以帮助我们更加轻松地使用ORM框架等等。
总的来说,Spring框架可以帮助我们更加轻松地开发Java应用程序,提高开发效率,减少代码冗余和重复,使得应用程序更加灵活和易于维护。
2 Spring包含哪些模块
Spring框架包含了很多模块,以下是一些重要的Spring模块:
Spring Core:Spring框架的核心模块,提供了依赖注入(DI)和控制反转(IoC)的功能,用于管理对象之间的依赖关系。
Spring MVC:基于MVC(Model-View-Controller)模式的Web框架,提供了用于处理请求、响应以及Web应用程序其他方面的API。
Spring Data:Spring框架的数据访问层模块,提供了通用的数据访问抽象层和一些特定数据访问技术的实现,如JPA、Hibernate等。
Spring Security:Spring框架的安全模块,提供了基于Spring框架的认证和授权功能,可以保护Web应用程序免受各种攻击。
Spring Integration:Spring框架的集成模块,提供了一些集成技术的实现,如消息队列、Web服务、FTP等。
Spring Batch:Spring框架的批处理模块,提供了处理大规模数据批处理的功能,包括事务处理、并发处理、失败处理等。
Spring Cloud:Spring框架的云原生模块,提供了在云环境下构建微服务应用程序所需的一些基础设施和工具,如服务注册、配置中心、断路器等。
除了以上列举的模块,Spring框架还包含了很多其他的模块,比如Spring WebFlux、Spring Test、Spring WebSocket等,每个模块都提供了一些特定的功能和工具,可以帮助开发者更加方便地开发Java应用程序。
3 什么是IOC
IoC(Inversion of Control)是一种设计模式,它将对象之间的依赖关系的管理交给框架来处理,从而实现对象之间的松耦合和可维护性。
传统的编程模式中,对象之间的依赖关系是由对象自己来管理的,当对象A需要对象B的协助完成某个功能时,对象A会主动创建对象B,然后在适当的时候调用对 象B的方法。这种方式会导致对象之间的依赖关系紧密耦合,使得代码难以维护和扩展。
在Spring框架中,实现IoC的方式是通过依赖注入(Dependency Injection,DI)来实现的。DI有三种实现方式:
-
构造函数注入(Constructor Injection):通过构造函数来注入依赖对象。
-
属性注入(Setter Injection):通过setter方法来注入依赖对象。
-
接口注入(Interface Injection):通过接口方法来注入依赖对象。
定义的Bean会被IOC容器读取并加载。当需要使用某个Bean时,容器会创建指定的Bean。
依赖注入:当IOC容器创建一个Bean时,它会检查该Bean所依赖的其他Bean是否已经创建,如果已经创建,则会将依赖的Bean注入到该Bean中,否则会等待所依赖的Bean创建完成后再注入依赖。(依赖注入是注入Bean内部的属性)
4 什么是AOP? 有哪些AOP的概念?
AOP(Aspect-Oriented Programming)是一种编程思想,它通过将应用程序分解成多个切面,来实现对应用程序进行横向切割的目的,从而实现代码的复用和系统的解耦。
AOP的核心思想是将与业务逻辑无关的代码,如日志、事务、异常处理等,从业务逻辑代码中分离出来,形成独立的模块,以便于复用和维护。
AOP的一些概念如下:
-
切面(Aspect):切面是一个模块化的横切关注点,它通过对某个点进行拦截,来实现对目标对象的增强。(切面中存放的是通知等方法的)
-
连接点(Join Point):连接点是在应用程序执行过程中能够插入切面的点,例如方法调用或异常处理等。(作用于要增强的方法)
-
切入点(Pointcut):切入点是一组连接点的集合,它定义了在哪些连接点处应用切面。
-
通知(Advice):通知是切面在连接点上执行的操作,例如在方法调用前、方法调用后、方法返回时或方法抛出异常时执行的操作。
-
织入(Weaving):织入是将切面应用到目标对象并创建新的代理对象的过程。织入可以在编译时、类加载时或运行时进行。
-
目标对象(Target Object):目标对象是应用程序中需要被增强的对象。
-
代理对象(Proxy Object):代理对象是一个中间件对象,它拦截对目标对象的访问并调用切面提供的通知。
通过AOP的概念,我们可以将应用程序按照不同的横向关注点进行切割,并将与业务逻辑无关的代码分离出来,从而提高应用程序的可维护性和可扩展性。常见的AOP框架有Spring AOP和AspectJ。
5 AOP 有哪些应用场景?
AOP(Aspect-Oriented Programming)可以在许多场景下被应用。以下是一些AOP的应用场景:
-
日志记录:在方法调用前后记录日志,用于排查错误和分析系统性能。
-
安全性控制:控制用户对系统中某些资源或方法的访问权限,确保系统安全。
-
事务管理:在方法调用前后开启、提交或回滚事务,确保数据的一致性和完整性。
-
缓存管理:通过在方法调用前检查缓存中是否有目标对象的缓存结果,减少系统的响应时间和网络开销。
-
性能监控:记录方法调用的时间、次数和异常等信息,以便于分析系统性能。
-
异常处理:在方法调用过程中捕获异常并记录或通知开发人员,以便于及时处理异常情况。
-
数据验证:在方法调用前对输入参数进行验证,确保输入数据的正确性和合法性。
-
代码复用:将与业务逻辑无关的代码抽离出来,以便于复用和维护。
6 AOP Advice通知的类型?
在AOP(Aspect-Oriented Programming)中,通知(Advice)是在切面(Aspect)中定义的一些方法,用于在连接点(Join Point)处执行特定的操作。通知可以分为以下几种类型:
-
前置通知(Before Advice):在连接点之前执行的通知,例如在方法调用前记录日志或开启事务等。
-
后置通知(After Advice):在连接点之后执行的通知,例如在方法调用后记录日志或提交事务等。
-
返回通知(After Returning Advice):在方法返回结果之后执行的通知,例如在方法调用后记录返回结果或关闭资源等。
-
异常通知(After Throwing Advice):在方法抛出异常时执行的通知,例如在方法调用抛出异常时记录异常信息或回滚事务等。
-
环绕通知(Around Advice):在方法调用之前和之后都可以执行的通知,它可以自由控制方法调用前后的逻辑,例如在方法调用前记录日志或在方法调用后提交事务等。
以上通知类型都是用于在连接点处执行特定的操作,并通过切面将这些通知应用到目标对象中。这些通知类型可以根据实际业务需求进行组合,从而实现对目标对象的增强,提高应用程序的可维护性和可扩展性。
7 Spring中的bean的作用域有哪些?
在Spring中,Bean的作用域(Scope)指定了在容器中创建的Bean实例的生命周期,不同的作用域决定了Bean实例的可见范围和生命周期长度。Spring框架支持以下五种Bean作用域:
-
singleton(单例):在整个应用中只创建一个Bean实例,并在容器启动时就创建,以后每次请求都返回同一个实例。
-
prototype(原型):每次请求都会创建一个新的Bean实例,适用于一些状态不可共享的Bean。
-
request(请求):在每个HTTP请求中创建一个Bean实例,该Bean实例仅在当前请求中有效,对于不同的请求,会创建不同的Bean实例。
-
session(会话):在每个HTTP Session中创建一个Bean实例,该Bean实例仅在当前Session中有效,对于不同的Session,会创建不同的Bean实例。
-
global-session(全局会话):在基于portlet的web应用中使用,该作用域仅在基于portlet的web应用中有效,一个portlet的多个请求共享一个Bean实例。
其中,单例(singleton)是默认的作用域,当没有指定作用域时,Spring会默认将Bean作为单例。除了全局会话作用域,其他四种作用域都只适用于Web应用。在Spring中,可以通过在Bean定义中指定scope属性来指定Bean的作用域。
在注解中,可以使用@Scope注解来指定Bean的作用域,如下所示:
java
@Component
@Scope("prototype")
public class ExampleBean {
// ...
}
**注:**需要注意的是,在单例作用域中,如果Bean有状态(stateful),则需要考虑线程安全问题,否则可能会导致多线程并发访问出现问题。因此,对于有状态的Bean,建议使用原型作用域(prototype)。
8 Spring中的单例bean的线程安全问题
在Spring中,单例Bean的线程安全问题是需要考虑的。由于单例Bean在容器启动时就会被创建,因此所有的请求都会共享同一个Bean实例。如果Bean有状态(stateful),即Bean的属性会随着请求的处理而改变,那么在多线程并发访问的情况下,就需要考虑线程安全问题。
在单例Bean中,如果有多个线程同时访问Bean实例并且Bean实例中有共享的数据,那么就可能出现数据不一致的情况,这是因为多个线程会竞争共享数据的访问权,导致数据出现冲突。为了解决这个问题,需要在多线程环境下保证Bean实例的线程安全。
有多种方式可以保证Spring中的单例Bean的线程安全:
-
在bean对象中尽量避免定义可变的成员变量(不太现实)。
-
在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)。
需要注意的是,Spring框架本身并不提供对单例Bean的线程安全保证,因此需要在编写代码时自行考虑和实现线程安全的措施。
9 spring bean 容器的生命周期是什么
此处先赋流程图片更为清晰,详细整理之后再出。
10 对于Spring MVC的了解
Spring MVC是基于MVC(Model-View-Controller)设计模式实现的一种Web应用程序开发框架。它是Spring Framework的一个重要组成部分,提供了一个灵活、松耦合、可扩展、高效的Web开发框架。
在Spring MVC中,M代表模型(Model),即数据模型;V代表视图(View),即用户界面;C代表控制器(Controller)
Spring MVC下我们一般把后端项目分为Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。
11 SpringMvc的工作原理
Spring MVC的工作原理可以分为以下几个步骤:
-
客户端发送请求,请求被前端控制器DispatcherServlet截获。
-
DispatcherServlet查询处理器映射HandlerMapping,根据请求URI找到对应的处理器Controller。
-
HandlerAdapter将请求发送给处理器Controller进行处理,Controller根据请求参数处理业务逻辑,调用业务逻辑层的Service。
-
Service处理业务逻辑,返回数据给Controller。
-
Controller将数据封装为ModelAndView对象,其中Model表示数据模型,View表示视图名称。
-
DispatcherServlet查询视图解析器ViewResolver,根据视图名称找到对应的视图View。
-
View渲染模型数据,将视图返回给DispatcherServlet。
-
DispatcherServlet将视图发送给客户端,完成请求响应。
在这个过程中,Spring MVC的核心组件包括:
-
DispatcherServlet:前端控制器,负责拦截所有请求并进行处理。
-
HandlerMapping:处理器映射,用于将请求映射到对应的处理器。
-
HandlerAdapter:处理器适配器,用于将请求发送给处理器进行处理。
-
Controller:处理器,用于处理具体的业务逻辑。
-
Service:业务逻辑层,负责处理具体的业务逻辑。
-
Model:数据模型,用于封装业务逻辑返回的数据。
-
View:视图,用于展示数据给用户。
-
ViewResolver:视图解析器,用于将视图名称解析为实际的视图对象。
Spring MVC的工作流程是非常灵活的,可以根据实际需求进行定制和扩展。开发人员可以自定义处理器映射、处理器适配器、视图解析器等组件,以满足不同的业务场景需求。同时,Spring MVC也提供了很多现成的插件和组件,如国际化插件、文件上传插件等,可以大大提高开发效率。
12 Spring框架中用到了哪些设计模式
Spring框架是一个非常重要的开源框架,它涉及到许多设计模式,以下是Spring框架中使用的一些设计模式:
单例模式:Spring框架中的bean默认是单例的,可以通过配置更改其作用域。单例模式保证了在整个应用程序中只有一个实例。
工厂模式:Spring框架中的BeanFactory是一个工厂模式的典型实现。BeanFactory负责实例化并管理应用程序中的对象。
代理模式:Spring框架中的AOP(面向切面编程)机制是通过代理模式来实现的。Spring中使用代理对象对目标对象进行包装,从而实现对目标对象的增强。
观察者模式:Spring框架中的事件驱动机制就是一个观察者模式的实现。事件源产生事件后,会通知已经注册的监听器进行处理。
模板方法模式:Spring框架中的JdbcTemplate
是一个典型的模板方法模式的实现。JdbcTemplate定义了一系列操作数据库的基本方法,而具体的实现则由其子类完成。
适配器模式:Spring框架中的HandlerAdapter
就是一个适配器模式的典型实现。HandlerAdapter负责将请求发送给处理器进行处理,从而使得不同类型的处理器可以被统一处理。
除了以上这些设计模式,Spring框架还使用了许多其他的设计模式,如策略模式、装饰器模式、命令模式等。这些设计模式的使用,使得Spring框架具有了更好的灵活性、可扩展性和可维护性。
13 Spring事务中的隔离级别有哪几种?
在Spring事务中,隔离级别用来描述并发事务之间的关系,它规定了一个事务对于数据的读取能够具有的隔离程度。Spring框架中提供了五个隔离级别:
-
Isolation.DEFAULT:默认隔离级别,由底层的数据库驱动决定隔离级别,通常为数据库的默认隔离级别。
-
Isolation.READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但未提交的数据。该级别可以产生脏读、不可重复读和幻读的问题。
-
Isolation.READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以避免脏读问题,但不可重复读和幻读问题仍然可能发生。
-
Isolation.REPEATABLE_READ:该隔离级别表示一个事务在执行过程中多次读取同一数据集时,其结果是一致的。该级别可以避免脏读和不可重复读问题,但仍然可能发生幻读问题。
-
Isolation.SERIALIZABLE:该隔离级别表示一个事务在执行过程中对于数据的修改会进行排队,即串行化执行,从而避免了脏读、不可重复读和幻读问题,但也降低了并发性能。
不同的隔离级别在解决并发事务问题时采用了不同的策略,为了保证应用程序数据的一致性和正确性,在选择隔离级别时需要根据具体的业务场景和需求进行选择。
14 Spring事务中有哪几种事务传播行为?
在Spring事务中,事务的传播行为指的是在一个事务方法调用另一个事务方法时,另一个事务方法如何处理事务的行为。Spring事务支持以下七种传播行为:
-
PROPAGATION_REQUIRED(默认值):如果当前存在事务,则在该事务中执行;否则,创建一个新的事务并在其中执行方法。
-
PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
-
PROPAGATION_MANDATORY:强制执行当前事务,如果当前没有事务,则抛出异常。
-
PROPAGATION_REQUIRES_NEW:创建新的事务,并在新事务中执行方法,如果当前存在事务,则暂停当前事务。
-
PROPAGATION_NOT_SUPPORTED:以非事务方式执行方法,如果当前存在事务,则暂停当前事务。
-
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
-
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务中执行;否则,执行与PROPAGATION_REQUIRED相同的操作。嵌套事务是当前事务的子事务,并与当前事务共享一部分数据源连接。如果嵌套事务失败,则仅回滚嵌套事务,而不会回滚当前事务。如果当前事务失败,则嵌套事务和当前事务都将被回滚。
这些传播行为可以使用@Transactional注解中的propagation属性来指定。
15 Spring事务什么时候会失效
spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了!常见情况有如下几种
-
发生自调用,类里面使用this调用本类的方法(this通常省略),此时这个this对象不是代理类,而是UserService对象本身!解决方法很简单,让那个this变成UserService的代理类即可!
-
方法不是public的:@Transactional只能⽤于public的方法上,否则事务不会生效,如果要用在非public方法上,可以开启 AspectJ 代理模式。
例如:如果某个方法是private的,那么@Transactional也会失效,因为底层cglib是基于父子类来实现的,子类是不能重载父类的private方法的,所无法很好的利用代理,也会导致@Transactianal失效
-
数据库不支持事务。
-
没有被spring管理。
-
异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)。
16 Spring中的事务是如何实现的
- Spring事务底层是基于数据库事务和AOP机制的
- 首先对于使用了@Transactional注解的Bean,Spring会创建一个代理对象作为Bean
- 当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解
- 如果加了,那么则利用事务管理器创建一个数据库连接
- 并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常重要的一步
- 然后执行当前方法,方法中会执行sql
- 执行完当前方法后,如果没有出现异常就直接提交事务
- 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
- Spring事务默认的隔离级别对应的就是数据库的隔离级别
- Spring事务的传播机制是Spring事务自己实现的,也是Spring事务中最复杂的
- Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开一个事务,那么实际上就是新建立一个数据库连接,在此新数据库连接上执行sql
17 Spring启动流程
在创建Spring容器,也就是启动Spring时:
- ⾸先会进行扫描,扫描得到所有的BeanDefinition对象,并存在一个Map中
- 然后筛选出非懒加载的单例BeanDefinition进行创建Bean,对于多例Bean不需要在启动过程中去进行创建,对于多例Bean会在每次获取Bean时利用BeanDefinition去创建
- 利用BeanDefinition创建Bean就是Bean的创建生命周期,这期间包括了合并BeanDefinition、推断构造方法、实例化、属性填充、初始化前、初始化、初始化后等步骤,其中AOP就是发⽣在初始化后这⼀步骤中
- 单例Bean创建完了之后,Spring会发布一个容器启动事件
- Spring启动结束
- 在源码中会更复杂,比如源码中会提供一些模板方法,让子类来实现,比如源码中还涉及到一些BeanFactoryPostProcessor和BeanPostProcessor的注册,Spring的扫描就是通过BenaFactoryPostProcessor来实现的,依赖注入就是通过BeanPostProcessor来实现的
- 在Spring启动过程中还会去处理@Import等注解