springboot基础详解
springboot基础详解
循环依赖
什么是循环依赖?
AB两个Bean之间相互注入
spring如何解决循环依赖
关键是提前暴露未完全创建的Bean
在spring中主要使用了三级缓存来解决循环依赖
- 一级缓存:用于存储完全实例化完成的Bean
- 二级缓存:用于存储尚未完全初始化,但已实例化的Bean,用于提前暴露对象,解决循环依赖
- 三级缓存:用于存储对象工厂,当需要时,可以通过工厂创建早期的Bean
解决步骤:
- Spring首先创建Bean实例,并存入三级缓存中
- 当一个Bean依赖另一个未初始化的Bean时,Spring会从三级缓存中获取Bean的工厂,并生成改Bean的代理对象
- 代理对象存入二级缓存,解决循环依赖
- 一旦所有依赖Bean被完全初始化,Bean将转移到一级缓存
解决循环依赖的流程如下:
- 实例化A对象,并创建
ObjectFactory
存入三级缓存。 - A在初始化时需要B对象,开始B的创建逻辑。
- B实例化完成,也创建
ObjectFactory
存入三级缓存。 - B需要注入A,通过三级缓存获取
ObjectFactory
生成A对象,存入二级缓存。 - B通过二级缓存获得A对象后,B创建成功,存入一级缓存。
- A对象初始化时,由于B已创建完成,可以直接注入B,A创建成功存入一级缓存。
- 清除二级缓存中的临时对象A。
构造方法出现了循环依赖怎么解决?
由于构造函数是bean生命周期中最先执行的,Spring框架无法解决构造方法的循环依赖问题。可以使用@Lazy
懒加载注解,延迟bean的创建直到实际需要时。
为什么Spring循环依赖需要三级缓存,二级不够吗?(to do)
二级缓存虽然能解决循环依赖问题,但在涉及到动态代理(AOP),直接使用二级缓存不做处理会导致我们拿到的Bean是未处理的原始对象。如果二级缓存中存放的都是代理对象,则违反了Bean的生命周期。
Spring IOC
什么是SpingIOC
Spring IOC是Spring框架的核心概念之一,它通过依赖注入实现。ICO让对象的创建和管理职责由容器负责,而不是由对象本身控制。
- 核心思想:控制反转意味着对象的创建和依赖关系由spring容器管理,而不是由程序代码直接控制。这种机制使得程序更加灵活和解耦,提升了代码的可维护性和扩展性。
- 依赖注入:通过构造器注入,setter注入或接口注入,将对象所需的依赖注入给它,而不是由对象自己创建
IOC的好处
- 降低耦合度
- 提高可测试性
- 增强灵活性
BeanFactory和FactoryBean
BeanFactory
BeanFactory就是IOC的底层容器。负责管理和配置应用中的Bean。提供了创建和管理Bean的基本功能。
- 核心概念:BeanFactory负责从配置源中读取Bean的定义,并负责创建和管理这些Bean的生命周期。
- 延迟加载:其的重要特性是延迟加载化,即它只会在Bean首次请求时才会实例化该Bean,而不是在容器启动时就立即创建所有的Bean。
FactoryBean
FactoryBean是Spring提供的一个特殊接口,允许开发者通过自定义的逻辑创建复杂的Bean示例。与普通的Bean不同,通过FactoryBean创建的Bean不一定是FactoryBean本身,而是它生产的对象。
- 核心概念:FactoryBean是一个实现了FactoryBean
接口的Bean,通过它可以自定义复杂对象的创建逻辑。Spring容器会调用getObject()来获取实际的Bean的示例。
Spring Bean的生命周期
- 通过
BeanDefinition
获取bean的定义信息。 - 调用构造函数实例化bean。
- 进行bean的依赖注入,例如通过setter方法或
@Autowired
注解。 - 处理实现了
Aware
接口的bean。 - 执行
BeanPostProcessor
的前置处理器。 - 调用初始化方法,如实现了
InitializingBean
接口或自定义的init-method
。 - 执行
BeanPostProcessor
的后置处理器,可能在这里产生代理对象。 - 最后是销毁bean。
Spring有几种注入方式?
- 构造器注入,通过构造函数将依赖注入到 Bean 中。这是 Spring 官方推荐的方式,因为它可以确保依赖不可变,并且适合强制依赖的场景。
- Setter注入,在类中定义 Setter 方法,Spring 容器会调用这些方法并传入依赖。
- 字段注入,在字段上使用
@Autowired
注解,Spring 容器会自动注入依赖。 - 方法注入,通过任意方法将依赖注入到 Bean 中。这种方式较少使用,但在某些特殊场景下有用。
- 接口回调注入,通过实现特定接口的方式将依赖注入到 Bean 中。这种方式较为复杂,Spring 中较少使用。
Spring中Bean的作用域有哪些
在Spring配置中,我们可以通过scope属性来定义SpringBean的作用域,可以接受5个内键,分别代表5种作用域类型:
- singleton,用来定义一个Bean为单例,也就是说在SpringIoC容器中仅有唯一的一个实例对象,Spring中的Bean默认都是单例。它的作用域范围是ApplicationContext容器。
- prototype,用来定义一个Bean实例,也就是说在每次请求获取Bean的时候都会重新创建一个Bean实例对象,因此每次获取的实例对象都是不同的。它的作用域范围是调用getBean()方法直至获取对象。
- request,作用域范围仅在request中的Bean。
- session,作用域范围仅在session中的Bean,从浏览器中首次访问至浏览器关闭。
- globalSession,作用域范围是整个WebApplicationContext容器。
Spring MVC
它是Spring基于MVC模式来Web应用的模块,将请求处理流程分为三层:模型层(Model),视图层(View)和控制层(Controller),提供了一种松耦合的方式将用户请求,业务逻辑和视图渲染分离开来。
工作流程
- 客户端请求:浏览器向服务器发送HTTP请求
- DispatcherServiet:所有的请求首先由 Spring MVC 的核心前端控制器 Dispatcherservlet 接收,它充当整个流程的调度中心。
- 处理器映射 (Handler Mapping): pispatcherservlet 根据请求的 URL 使用处理器映射器找到对应的控制器(Controller)
- 控制器(Controler):控制器接收请求并处理业务逻辑,通常通过注解@contro1ler 和 @Requestmapping定义请求的映射方法。
- 模型和视图(ModelAndView):控制器处理完业务逻辑后,将数据封装到模型对象中,并指定返回的视图名称。
- 视图解析器 (ViewResolver): pispatcherservlet 调用视图解析器,将逻辑视图名称解析为实际的视图,如 JSP、Thymeleaf 等模板引擎。
- 视图渲染:视图渲染引擎根据模型中的数据生成 HTML 页面并返回给客户端。
框架篇汇总
Spring和Spring Boot框架的优势
Spring框架的优势
- 依赖注入与控制反转:通过依赖注入(DI) 和控制反转(IoC)机制。。。
- 面向切面编程(AOP):Spring支持面向切面编程,允许将横切关注点(如日志记录、事务管理、权限控制等)从业务逻辑中分离出来,以切面的形式进行统一处理。这样使业务代码逻辑更加清晰简洁,提高了代码的可读性和维护性。比如可以通过切面来统一记录所有业务方法的执行日志,而不需要在每个业务方法中都编写重复的日志记录代码。
- 丰富的框架集成:Spring提供了与各种其他框架的良好集成支持。比如mybatis等
Spring Boot框架的优势:
- 快速构建项目:Spring Boot提供了大量的自动配置功能,能够根据项目的依赖和配置自动配置Spring应用的各种组件,大大减少了项目的配置工作量,提高了开发效率。例如只需要在项目中添加Spring Boot的Web依赖,就可以快速创建一个可以运行的Web应用,无需配置Tomcat等相关组件。
- 内置服务器:Spring Boot内置了如Tomcat,Jetty等服务器,使得应用可以直接以可执行JAR或WAR包的形式运行,简化了应用的部署过程,提高了项目的可移植性。
- 监控和管理:
Spring框架中的单例bean是线程安全的吗
不是线程安全的。当多用户同时请求一个服务时,容器会给每个请求分配一个线程,这些线程会并发执行业务逻辑。如果处理逻辑中包含对单例状态的修改,比如修改单例的成员属性,就必须考虑线程同步问题。Spring框架本身并不对单例bean进行线程安全封装,线程安全和并发问题需要开发者自行处理。
通常在项目中使用的Spring bean是不可变状态(如Service类和DAO类),因此在某种程度上可以说Spring的单例bean是线程安全的。如果bean有多种状态(如ViewModel对象),就需要自行保证线程安全。最简单的解决办法是将单例bean的作用域由“singleton”变更为“prototype”。
什么是AOP?
AOP,即面向切面编程,在Spring中用于将那些与业务无关但对多个对象产生影响的公共行为和逻辑抽取出来,实现公共模块复用,降低耦合。常见的应用场景包括公共日志保存和事务处理。
项目中对AOP的使用
在后台管理系统中使用AOP来记录系统操作日志。主要思路是使用AOP的环绕通知和切点表达式,找到需要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,例如类信息、方法信息、注解、请求方式等,并将这些参数保存到数据库。
spring中的事务如何实现
Spring实现事务的本质是利用AOP完成的。它对方法前后进行拦截,在执行方法前开启事务,在执行完目标方法后根据执行情况提交或回滚事务。
Spring中事务失效的场景有哪些
在项目中,我遇到过几种导致事务失效的场景:
- 如果方法内部捕获并处理了异常,没有将异常抛出,会导致事务失效。因此,处理异常后应该确保异常能够被抛出。
- 如果方法抛出检查型异常(checked exception),并且没有在
@Transactional
注解上配置rollbackFor
属性为Exception
,那么异常发生时事务可能不会回滚。 - 如果事务注解的方法不是公开(public)修饰的,也可能导致事务失效。
SpringMVC的执行流程?
SpringMVC的执行流程包括以下步骤:
- 用户发送请求到前端控制器
DispatcherServlet
。 Dispatcher``Servlet
调用HandlerMapping
找到具体处理器。HandlerMapping
返回处理器对象及拦截器(如果有)给DispatcherServlet
。DispatcherServlet
调用HandlerAdapter
。HandlerAdapter
适配并调用具体处理器(Controller)。- Controller执行并返回
ModelAndView
对象。 HandlerAdapter
将ModelAndView
返回给DispatcherServlet
。DispatcherServlet
传给ViewResolver
进行视图解析。ViewResolver
返回具体视图给DispatcherServlet
。DispatcherServlet
渲染视图并响应用户。
SpringMVC的执行流程?
Spring Boot的自动配置原理基于@SpringBootApplication
注解,它封装了@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
。@EnableAutoConfiguration
是核心,它通过@Import
导入配置选择器,读取META-INF/spring.factories
文件中的类名,根据条件注解决定是否将配置类中的Bean导入到Spring容器中。
Spring 的常见注解有哪些
pring的常见注解包括:
- 声明Bean的注解:
@Component
、@Service
、@Repository
、@Controller
。 - 依赖注入相关注解:
@Autowired
、@``Qualifier
、@Resource
。 - 设置作用域的注解:
@Scope
。 - 配置相关注解:
@Configuration
、@ComponentScan
、@Bean
。 - AOP相关注解:
@Aspect
、@Before
、@After
、@Around
、@Pointcut
。
SpringMVC常见的注解有哪些
SpringMVC的常见注解有:
@RequestMapping
:映射请求路径。@RequestBody
:接收HTTP请求的JSON数据。@RequestParam
:指定请求参数名称。@PathVariable
:从请求路径中获取参数。@ResponseBody
:将Controller方法返回的对象转化为JSON。@RequestHeader
:获取请求头数据。@PostMapping
、@GetMapping
等。
Springboot常见注解有哪些
Spring Boot的常见注解包括:
@SpringBootApplication
:由@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
组成。- 其他注解如
@RestController
、@GetMapping
、@PostMapping
等,用于简化Spring MVC的配置。
MyBatis执行流程?
MyBatis的执行流程如下:
- 读取MyBatis配置文件
mybatis-config.xml
。 - 构造会话工厂
SqlSessionFactory
。 - 会话工厂创建
SqlSession
对象。 - 操作数据库的接口,
Executor
执行器。 Executor
执行方法中的MappedStatement
参数。- 输入参数映射。
- 输出结果映射。
Mybatis是否支持延迟加载
MyBatis支持延迟加载,即在需要用到数据时才加载。可以通过配置文件中的lazyLoadingEnabled
配置启用或禁用延迟加载。
延迟加载的底层原理知道吗?
延迟加载的底层原理主要使用CGLIB动态代理实现:
- 使用CGLIB创建目标对象的代理对象。
- 调用目标方法时,如果发现是null值,则执行SQL查询。
- 获取数据后,设置属性值并继续查询目标方法。
Mybatis的一级、二级缓存用过吗?
MyBatis的一级缓存是基于Perpetual``Cache
的HashMap本地缓存,作用域为Session,默认开启。二级缓存需要单独开启,作用域为Namespace或mapper,默认也是采用PerpetualCache
,HashMap存储。
事务
Spring中的事务传播行为有哪些
事务传播:在日常开发中,当多个声明了事务的方法相互调用时,会存在嵌套两个或者两个以上事务的情况,事务传播行为就是指这些事务之间的传播规则。
事务嵌套:在Spring中,一共定义了7种事务嵌套传播行为:
- REQUIRED,他是Spring默认的事务传播行为。表示如果当前存在事务,则加入这个事务,如果不存在则新建。
- REQUIRE_NEW,不管存不存在事务都会新建一个事务,新建的事务和原来的事务之间相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交。
- NESTED,如果当前存在事务,则嵌套在当前事务中执行,没有则新建。类似于REQUIRE_NEW。
- SUPPORTS,它表示支持当前事务,如果不存在当前事务,则以非事务的方式执行。
- NOT_SUPPORTED,表示非事务的方式执行,若当前不存在事务,则抛出异常。
- MANDATORY,强制事务执行,若当前不存在事务,则抛出异常。
- NEVER,以非事务的方式执行,如果当前存在事务,则抛出异常。
Spring中事务失效的原因有哪些
主要有以下8个:
- 方法没有被public修饰
- 类没有被Spring托管
- 不正确的异常捕获
- 同一类中的方法调用
- propagation事务传播行为配置错误
- rollbackFor参数错误
- 没有配置事务管理器
- 数据库本身不支持事务