1.说说什么是IOC?
- IOC作为Spring的核心技术模块,其主要是讲对象的实例过程交由容器进行管理,而无需我们开发者去处理对应的实例。
- 通过反射创建对象,由容器管理对象生命周期和依赖关系。
- 当然在里面不同Bean之间存在着DI,其实现原理就是通过反射,动态的向对象在注入自己所需要的对象
2.说一下AOP是什么?
-
将一些常用的逻辑进行封装,使开发者专注于业务逻辑,更容易解耦。
-
封装的逻辑一般有拦截器、校验器、日志、全局异常处理等
-
切面(定义方法),切点(定义注解),连接点(定义程序进入切面的点)
-
通知:前置before,后置after,环绕around
-
动态代理分两个,一个是jdk代理,一个是cglib代码,两个代理的区别如下:
- jdk代码是基于接口 的,但凡该接口实现了的方法被使用,都会调用对应的切面逻辑,适合日志统一、权限检测等情况。使用Java的反射机制,动态生成一个实现了指定接口的代理类。内存占用低。
- cglib代码需要精确在具体的类,能够更加细腻的决定哪些类在使用时被代理。通过字节码技术,在运行时生成一个目标类的子类。内存占用高且性能开销大。
3.说一下Beanfactory 和 FactoryBean的区别是什么?
通过Bean Factory进行统一管理Bean的获取,通过FactoryBean你可以控制对象如何创建,而ObjectFactory借助Scope接口自定义scope你可以控制对象的创建时机
-
BeanFactory:
- 一个工厂类接口
- 负责管理和创建 Bean 的基本容器
- BeanFactory–>SpringIoC容器顶级接口,定义了对单个bean的获取,对bean的作用域判断,获取bean类型,获取bean别名的功能
- ListableBeanFactory–>扩展了BeanFactory接口,并提供了对bean的枚举能力
- HierarchicalBeanFactory–>扩展了BeanFactory接口,并提供了访问父容器的能力
- AutowireCapableBeanFactory–>扩展了BeanFactory接口,并提供了自动装配能力
- ConfigurableBeanFactory–>扩展了HierarchicalBeanFactory,并提供了对容器的配置能力
- ConfigurableListableBeanFactory–>扩展了ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory接口,并提供了忽略依赖,自动装配判断,冻结bean的定义,枚举所有bean名称的功能
-
FactoryBean
- 一个实现了FactoryBean<T>接口的Bean
- 允许自定义 Bean 的创建逻辑,返回任意类型的对象,例如可以在创建过程中添加一些逻辑(如记录日志、处理异常等)。
- 当从
BeanFactory
获取这个 Bean 时,实际上得到的是FactoryBean
的getObject()
方法返回的对象,而不是FactoryBean
本身
-
ObjectFactory:
- 主要用于延迟对象的创建,创建时机由 Scope 接口控制,可以根据需要在不同的上下文中创建对象
- 适合用于场景中需要动态获取 Bean 的情况
- 在依赖注入时,可以通过调用
objectFactory.getObject()
来创建目标对象。 - 在创建代理对象时,
ObjectFactory
允许在 Bean 还未完全初始化时提前暴露对象。这使得在 AOP 场景中,能够注入代理对象而不是原始对象,确保切面逻辑能够生效
4.说一下Bean的生命周期?
大致就是我程序启动后,通过 loadBeanDefinitions 扫描所有xml配置、注解将Bean记录在beanDefinitionMap中,通过 createBean 遍历 beanDefinitionMap 创建bean,然后就是容器通过 createBeanInstance 进行对象构造,然后进行属性填充,当然属性填充的前后是有一些 XXawarepostprocessor方法对bean进行预处理,然后就是初始化,初始化前后也有对应的后置处理器,然后就是如果有实现InitializingBean接口,那么可以通过afterPropertiesSet方法进行属性自定义填充,最后就是销毁,当然在销毁之前也是有对应的接口方法执行
Bean的生命周期 ——五步骤
- 实例化
- 依赖注入
- 初始化
- 使用Bean
- 销毁Bean
Bean的生命周期 ——七步骤
- 实例化
- 依赖注入
- 初始化前 BeanPostProcessor before方法
- 初始化
- 初始化后 BeanPostProcessor after方法
- 使用Bean
- 销毁Bean
Bean的生命周期 ——十步骤
- 实例化
- 依赖注入
- BeanNameAware BeanFactoryAware接口方法执行
- 初始化前 BeanPostProcessor before方法
- InitialingBean接口方法执行
- 初始化
- 初始化后 BeanPostProcessor after方法
- 使用Bean
- DisposableBean接口方法执行
- 销毁Bean
Bean的生命周期——完整的步骤
- loadBeanDefinitions —— 扫描所有xml配置、注解将Bean记录在beanDefinitionMap中
- 加载定义 BeanDefinition #createBean ——遍历 beanDefinitionMap 创建bean
- InstantiationAwareBeanPostProcessor #postProcessBeforelnstantiation——主要来获取Bean实例,如果找不到就执行接下来操作,找到就跳过下面的操作;
- AutowiredAnnotationBeanPostProcessor #determineCandidateConstructors——决定选择哪一个构造器
- 实例化 ——对Bean进行构造器实例化
- InstantiationAwareBeanPostProcessor #postProcessAfterlnstantiation——在 Bean 实例化后进行检查和处理
- InstantiationAwareBeanPostProcessor #postProcesslnstantiation——在依赖注入开始前进行额外的配置
- 依赖注入(属性赋值)——为Bean内部所需的属性进行赋值
- BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 接口方法执行——通过 invokeAwareMethods 方法允许 Bean 获取其名称、BeanFactory 和类加载器的引用
- 初始化前 BeanPostProcessor before方法——在 Bean 初始化之前执行,允许进行一些准备工作或修改 Bean
- 初始化—— invokeInitMethods调用
- InitialingBean接口方法执行——Bean 实现了
InitializingBean
接口,调用其afterPropertiesSet()
方法进行自定义初始化 - 初始化后 BeanPostProcessor after方法——在 Bean 初始化后执行,允许进行后处理操作,包含着AOP的操作
- 使用Bean
- Scope为 singleton的就返回Bean给用户,并存入缓存池;
- prototype bean返回给用户,剩下生命周期用户控制
- DisposableBean接口方法执行
- 销毁Bean
Bean级生命周期方法: Bean 类直接实现接口的方法,这些方法只对当前 Bean 生效。
BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
、InitializingBean
、DisposableBean
Aware 类型的接口:能够拿到 Spring 容器中的一些资源,Aware 之前的名字就是可以拿到什么资源,所有的 Aware 方法都是在初始化阶段之前调用的
。
5.@Resource 和 @Autowire 的区别是什么?
装配方式不一样
- @Resource注解读取先从对象的名称去查找,查找不到就根据其类型去查找;
- 位于javax.annotation里面的jar包
- @Autowire默认根据类型去查找,如果类型有多个实现的话,就根据名称去查找
- 通过@Qyalifier注解去规定调用哪一个Bean
- 位于spring框架下bean的jar包
6.@Componse和@Bean的区别是什么?
- 两者都能被容器识别作为Bean,不过两者的用法不一样,@Bean的灵活性更高;
- @Componse注解书写在类上面,在程序启动后可以被IOC容器识别并纳入容器内部
- @Benn注解书写在对象上,并且需要在含有@Configure注解的类里面书写,这个Configure注解相当于配置文件xml的功能,然后里面的@bena注解书写可以灵活的的放回,特别是面对第三方的jar包时,我们要灵活使用里面的Bean对象,那么就可以使用该@Bean注解
7.什么是反射?
反射是一种在运行时动态访问类的信息、方法和字段的机制。特别是在DI中,反射允许程序在运行时加载和使用已经存在的字节码文件,可以动态调用类的方法和访问字段,而不需要在编译时确定具体的类和方法。
8.什么是事务?Spring事务和MySQL的事务之间有什么区别?
-
事务是指一组操作的集合,这些操作要么全部成功,要么全部失败。事务的主要特性可以用 A(Atomicity)C(Consistency)I(Isolation)D(Durability) 原则来描述;
-
Spring的事务允许通过注解或xml进行控制且Spring的事务具备传播性(
REQUIRED
、REQUIRES_NEW
、NESTED
),允许方法定义事务的边界,允许复杂的业务逻辑,如果当前的没事务就new一个,如果有则加入事务; -
Mysql事务由数据库引擎管理,直接在数据库层控制,直接处理 SQL 语句的执行、提交和回滚。
-
Spring 的事务回滚会同时触发数据库的回滚,确保所有操作的一致性。SQL 语句自身不具备回滚能力,而是依赖事务控制
9.如果出现循环依赖怎么解决?
- 加@lazy注解
- 如果a依赖b,b依赖c,c依赖a,将中间的b换一种方式去实例
- 把依赖方法直接写入
- 使用中间体,避免直接依赖
10.说一下SpringMvc的执行流程和调用过程。
DispatcherServlet
是 Spring MVC 的核心,负责请求的接收、处理、分发和响应,是实现 MVC 模式的关键组件
执行过程:
1、用户发送请求到前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用处理映射器HandlerMapping
3、处理映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包含处理器对象和处理器拦截器)返回给DispatcherServlet
4、DispatcherServlet根据处理器Handler获取对应的适配器
5、HandlerAdapter调用处理器Handler
6、Handler(Controller)执行完成后返回ModelAndView
7、HandlerAdapter返回ModelAndView
8、DispatcherServlet统一将返回的ModelAndView派送到ViewResolve(视图解析器)解析
9,视图解析器解析之后返回View
10、对View进行渲染
11、响应用户
调用过程:
DispatcherServlet默认使用WebApplicationContext作为上下文,因此我们来看一下该上下文中有哪些特殊的Bean:
(1)控制层:
1、Controller:处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理;
2、HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;
3、HandlerAdapter:HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter将对实现了Controller接口的Bean进行适配,并且掉处理器的handleRequest方法进行功能处理;
(2)视图层:
4、ViewResolver:ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为jsp视图;
5、LocalResover:本地化解析,因为Spring支持国际化,因此LocalResover解析客户端的Locale信息从而方便进行国际化;
6、ThemeResovler:主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;
7、MultipartResolver:文件上传解析,用于支持文件上传;
8、HandlerExceptionResolver:处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的界面(而不是给用户看到具体的错误信息);
9、RequestToViewNameTranslator:当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名;
(3)其他:
10、FlashMapManager:用于管理FlashMap的策略接口,FlashMap用于存储一个请求的输出,当进入另一个请求时作为该请求的输入,通常用于重定向场景,用于短期数据传递。
11.Spring Boot容器的理解,其加载过程是什么样子的。
SpringBoot容器基于loc进行管理Bean生命周期和依赖关系
执行过程如下:
- 调用main方法中的run方法
- 创建springApplication实例
- 根据程序的配置,准备上下文
- 加载配置文件
- 自动配置
- *创建Bean
- *依赖注入
- *初始化
- *上下文刷新等待请求(确保所有Bean准备就绪)
- 事件发布,通知应用准备就绪
- 运行应用
12.tomcat是怎么加载进入容器里面的?
执行过程如下:
- 调用main方法中的run方法
- 创建springApplication实例
- 根据程序的配置,准备上下文
- 加载配置文件
- 自动配置
- *创建Tomcat实例 并配置其端口路径等信息
- *注册servlet 和 filter(请求预处理、权限控制)
- *通过webapplication初始化容器
- *上下文刷新确保所有bean准备就绪
- 事件发布,通知应用准备就绪
- tomcat接受请求转发给spring的dispatchservlet,然后分到给不同的hander进行处理
- hander处理结束返回给tomcat再返回给客户端
13.Spring的一、二、三级缓存是什么?
三级缓存主要是解决循环依赖问题。
- 一级存储完整的bean;
- 二级存储未完全实例化的暴露的Bean;
- 三级存储对应Bean的ObjectFactory;
循环依赖场景:
- 设 A 依赖 B,B 依赖 A。
- 当创建 A 时,发现 B 尚未完成,于是将 A 的工厂放入三级缓存。
- 创建 B 时,同样发现 A 尚未完成,B 的工厂也放入三级缓存。
处理过程: - A 在创建过程中进入三级缓存,随后尝试填充属性,发现需要 B。
- 创建 B 时,发现 A 的工厂在三级缓存中,便将 A 放入二级缓存。
- B 完成初始化后,放入一级缓存。
- A 通过一级缓存获取到 B 的完整实例,完成自身初始化。
14.Applicationcontext与Beanfactory的区别是什么?
- BeanFactory是Spring底层最基本的接口,这个容器用来管理Bean的加载,实例化,控制生命周期等功能,其Beanfactroy采用延迟注入Bean,只有在bena被使用的时候才会进行注入,优点是不用一次性加载,缺点如果最后调用错误才抛出异常,没办法知道程序潜在的问题
- ApplicationContext 是 BeanFactory的子类,其特点是当容器被加载时,一次性加载所有的Bean,这样可以发现程序潜在的问题,但是随着而来的就是内存占用较大。
15.Spring Bean的作用域有哪些?
五大作用域:
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
- session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
- global-session: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。