spring-八股文

  1. 对IOC的理解
  2. inverse of control,控制翻转,将bean的生成交给spring管理,例如,@autowired自动装配的mapper层对象。
    好处:单例bean可以有效复用,减少对象生成的时间成本。各种bean还有自身的应用场景。
    
  3. 单例bean与单例模式
  4. spring自动装配出来的对象全都会指向同一个单例bean,不强制约束用户不可创建第二个对象。
    单例模式针对的是类而言的,如果某个类应用了单例模式,那么这个类就不可能创建出第二个对象,所有该类的引用都会指向同一个对象,不管是spring自动装配还是用户自己new。
    
  5. spring事务传播机制
  6. 事务注解对应的方法A,调用了方法B,那么B是共用一个事务的逻辑,还是单独开一个新事务,,,,这些策略取决于两个方法定义的事务传播类型
    
    1. REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则⾃⼰新建⼀个事务,如果当前存
    在事务,则加⼊这个事务
    2. SUPPORTS:当前存在事务,则加⼊当前事务,如果当前没有事务,就以⾮事务⽅法执⾏
    3. MANDATORY:当前存在事务,则加⼊当前事务,如果当前事务不存在,则抛出异常。
    4. REQUIRES_NEW:创建⼀个新事务,如果存在当前事务,则挂起该事务。
    5. NOT_SUPPORTED:以⾮事务⽅式执⾏,如果当前存在事务,则挂起当前事务
    6. NEVER:不使⽤事务,如果当前事务存在,则抛出异常
    7. NESTED:如果当前事务存在,则在嵌套事务中执⾏,否则REQUIRED的操作⼀样(开启⼀个事
    务)
    
  7. spring事务什么时候会失效-√
  8. 数据库:数据库如果不支持事务,那么spring事务就会失效
    Java:
    类:事务所在类没有对应的注解,spring没有在容器里面生成该类的bean[类上面没有component之类的注解]
    方法:方法上没有加上事务注解或者方法的权限修饰符不是public
    调用:调用方法没有使用代理对象,而是通过原对象调用的方法。[自己new]
    
  9. spring中创建的bean,生命周期有哪些-※
  10. 1.推断构造方法
    2.实例化
    3.依赖注入[构造方法可能需要部分外部注入属性;成员变量中依赖于其他类,等等多种需要将其他实例注入的情况]
    4.处理@postConstruct注解,构造之后还可以执行的自定义处理
    5.处理initializingBean接口复写内容,如果实现了该接口的话[前面就是bean的实例化,这一步就是bean的初始化,这就是两者的区别]
    6.生成代理对象,最后生成bean
    
  11. spring中的bean是线程安全的吗?
  12. 如果bean上有状态,就不是线程安全的
    如果bean上没有状态,就是线程安全的
    
  13. applicationContext和beanFactory有什么区别?
  14. beanFatory的功能,applicationContext都有,但applicationContext还有其他功能[获取系统环境变量、事件发布]
    
  15. spring中的事务是如何实现的?
  16. 事务这个概念是数据库层面的,spring只是基于数据库的事务功能,对其进行了扩展,提供了方便开发人员操作事务的方式
    
    1.针对使用了Transaction注解的bean,生成代理对象
    2.当调用了事务方法,创建新的数据库连接,并关掉自动提交功能
    3.然后执行当前方法,会执行若干SQL
    4.执行以后,没有发生异常,直接提交该事务
    5.执行以后,发生异常,进行回滚[需要回滚的异常级别,在@Transactional注解中的rollbackFor属性配置]
    
  17. spring容器的启动流程是怎样的?(IOC的工作流程)
  18. 定义:IOC,inverse of control,即控制反转,将bean的创建管理交给spring,有利于单例bean的复用,单例bean还能减少对象创建的时间成本,还能降低对象与对象之间的耦合性。
    
    
    1.扫描所有beanDefinition对象,将其保存到beanDefinitionMap集合中
    2.通过对beanDefinitionMap遍历,可以逐个实例化bean对象,推断构造方法-实例化-依赖注入-postConstruct注解-beanInition接口复写方法-生成代理对象-生成bean
    3.applicationContext发布spring容器启动事件
    4.多例bean与lazy修饰的单例bean只有使用到的时候,才真正初始化完成,在使用之前,仅有一个代理对象作为依赖注入
    

    工作流程:

    graph TD IOC容器初始化,解析注解,配置类等方式得到beanDefinition,将其保存到beanDefinitionMap集合中 --> 通过对beanDefinitionMap遍历,可以逐个实例化bean对象 --> bean的初始化以及依赖注入,如果有循环依赖就用三级缓存-singletonObjects-earlysingletonObjects-singletonFactories --> 通过注解或者beanFactory可以使用bean,同时懒加载的bean对象也是使用阶段的时候,才真正初始化完成的.使用之前,只是通过代理对象先生成对应的实例对象.
  19. spring用到了哪些设计模式?
  20. 1.beanFactory-工厂模式
    2.单例bean-单例模式
    3.代理对象-代理模式
    
  21. spring boot常用注解及其底层实现-※
  22. 常用注解有
    1.@bean 方法级注解,可用于对应的单例bean对象
    2.@autowired 用于生成单例bean的引用;要求原类增加类注解例如component\service\controller\mapper等来交给spring托管
    3.@controller\@service\@mapper,这三都是类注解,用于指定controller、service、mapper类,从而可以自动将请求匹配到controller对应方法上,以及自动调用对应的SQL
    4.@GetMapping,@PostMapping,用于指定请求的匹配类型,方法接收get请求、post请求等等
    
    具体实现 不太清楚
    
  23. springboot是如何启动Tomcat?
  24. 1.检索是否有tomcat依赖
    2.将tomcat实例化,并加入到spring容器中
    3.启动tomcat实例
    
  25. spring cloud 有哪些组件?
  26. springboot如何解决跨域问题?
  27. 1.实现webMvcConfigurer接口,实现addCoresMapping方法
    2.利用注解@CrossOrigin,加到spring boot容器对象上即可
    
  28. @component和@bean之间的区别
  29. 1.用途不同:component声明的是一个普通类,而bean则是在配置类中声明和配置一个bean对象
    2.声明不同:component应用的是类 ,而bean应用的是方法上
    3.控制不同:component的创建配置过程是由spring管理的,而bean的创建配置过程允许开发人员手动控制
    
  30. 过滤器和拦截器之间的区别
  31. 过滤器:filter
    拦截器:interceptor[例如操作日志记录的AOP]
    
    1.filter在请求达到servlet之前,interceptor在servlet容器收到请求之后,进入controller之前运行
    2.filter依赖于servlet容器[实现的是javax.servlet.Filter接口],interceptor是spring的一个组件[实现的是handlerinterceptor接口]
    3.filter基于函数回调,interceptor基于java反射机制
    
    filter-->interceptor.prehandle-->handler-->interceptor.posthandler-->interceptor.afterCompletion-->filter
    
  32. @Async一定会异步执行
  33. A:被@Async标记的方法
    B:调用A的方法
    
    @Async:
    这是一个标记方法为异步执行的注解
    spring框架会默认使用一个线程池来管理异步方法的执行,spring框架将A封装成代理对象[这也就是为什么A必须是托管的bean对象的原因],B调用A的时候,实际上都是使用线程池来执行A的方法体
    
    这个注解只是标记A是异步执行的,真正是否异步执行,取决于:
    
    一、要打开功能-@EnableAsync-@Async
    二、必须能创建代理对象
    2.1 类:spring托管
    2.2 方法:必须是public[新版spring貌似protected也可以]
    2.3 方法:不能是静态-否则无法创建子类来代理[Spring用的应该是CGLIB]
    
    三、必须要使用代理对象
    3.1 调用方与被调用方不能在同一个对象内-否则会绕过代理对象
    
    四、合理配置线程池
    4.1.使用@Async必须配置一个合适的线程池来执行异步方法。
    [一般spring默认就配置了线程池,但是默认的线程池不是真正的线程池,并没有真正复用线程]
    [也可以自定义重新指定线程池,通过对ThreadPoolTaskExecutor进行封装即可,指定
    1.setMaxPoolSize
    2.setCorePoolSize
    3.setThreadNamePrefix
    4.initialize
    即可将对象返回给注解--->@Async("asyncTaskExecutor")
    ]
    
  34. 为什么有些公司会禁用Transaction注解
  35. 事务注解主要存在以下隐患
    正常情况:如果事务耗时较长,那么占用锁时间也会较长,甚至有可能耗尽数据库连接池,影响程序的正常执行
    非正常情况:如果事务中还存在嵌套情况,有可能造成未知的异常情况
    项目:随着项目的复杂程度提升,事务的控制逻辑越来越复杂,降低了代码的可读性与可维护性
    
  36. @Conditional的作用
  37. 作用是给 bean是否装载到容器 增加一个条件判断
    入:注解接受一个或多个实现了condition接口的类;condition接口里面有一个matches方法需要重写
    出:可以修饰在类上面,也可以修饰在方法上面。
    
  38. springMVC的理解
  39. springMVC是spring生态下,基于MVC架构设计的webFramwork模块,是一种web框架
    M:model,模型
    V:view,视图
    C:controller,控制器
    其组件主要有:前端控制器(dispatcherServlet),控制器映射器(handlerMapping),控制器适配器(handlerAdapter),视图解析器(viewResolver)
    其主要执行流程见《spring MVC执行流程》
    
  40. spring MVC执行流程
  41. graph TD 用户发送请求 --> 前端控制器 --> |请求获取处理器|处理器映射器,MAP结构,用于找到URL对应的controller 前端控制器 --> |请求执行处理器|处理器适配器,实际controller调用方,由于早期不止注解一种方式,这里是用来做兼容适配的 --> |调用处理器|处理器,开发实际编写的controller --> |逻辑视图和数据|处理器适配器,实际controller调用方,由于早期不止注解一种方式,这里是用来做兼容适配的 --> |逻辑视图和数据|前端控制器 前端控制器 --> |依据逻辑视图寻找物理视图|视图解析器
    graph TD 用户发送请求 --> dispatcherServlet --> |请求获取处理器|handlerMapping dispatcherServlet --> |请求执行处理器|handlerAdapter --> |调用处理器|controller,如果有拦截器,进入之前会先执行拦截器 --> |ModelAndView|handlerAdapter --> |ModelAndView|dispatcherServlet dispatcherServlet --> |ModelAndView转为View|viewResolver
  42. 什么是循环依赖?
  43. 循环依赖就是在spring在构建单例bean对象的时候,依赖注入阶段,A与B互相之间有依赖关系
    往A注入B的时候,单例池里面既没有A也没有B,触发B的构建,往B注入A的时候,由于单例池里面没有A,又会触发A的构建,
    从而导致无法正常实例化、初始化这些单例bean
    
  44. 什么是三级缓存?
  45. 三级缓存是解决循环依赖的一种解决方案
    第一级缓存 singletonObjects<beanName,单例 bean>:用于保证所有bean是单例的
    保存的是 经过完整生命周期,创建完成的单例bean对象
    
    第二级缓存 earlySingletonObjects<beanName,单例bean>:用于防止出现多代理问题
    保存的是,在出现循环依赖的情况下,自己都没有创建完,需要提前暴露给其他单例bean用的单例bean对象
    
    第三级缓存 singletonFactories<beanName,()->getEarlyBeanReference(beanName,mbd,bean)>:用于打破循环
    保存的是bean对应的普通对象,用于循环依赖的时候,能提供一个普通对象,用于生成代理对象
    
    基本流程:
    背景:A->B[A依赖于B]    A->C[A依赖于C]
    
    1.构建A的普通对象-->保存到第三级缓存,用于之后调用打破循环
    1.x 记录creatingset 判断循环依赖
    2.B依赖注入:
      2.1 构建B的普通对象-->保存到第三级缓存,用于之后调用打破循环
      2.2 找依赖对象A:单例池->earlySingletonObjects->singleFactories->返回代理对象->earlySingletonObjects
      2.3 依赖注入,@postConstruct,initializeBean接口实现,生成代理对象,放入单例池[AOP等一系列操作]
      2.4 生成的B代理对象返回给A
    
    3.C依赖注入:
      2.1 构建C的普通对象-->保存到第三级缓存,用于之后调用打破循环
      2.2 找依赖对象A:单例池->earlySingletonObjects
      2.3 依赖注入,@postConstruct,initializeBean接口实现,生成代理对象,放入单例池[AOP等一系列操作]
      2.4 生成的C代理对象返回给A
    
    4.通过earlyProxyReference判断是否需要继续AOP等操作
    5.取出earlySingletonObjects提前放入的代理对象,放入单例池[由于二级缓存里面存放的是三级缓存造出来的代理对象,三级缓存是通过当前的普通对象造的,因此,本质上应当是同一个对象引用]
    
  46. @Lazy的作用
  47. 1.当构造函数带参的时候,spring是无法通过三级缓存解决循环依赖的问题
    2.lazy可以通过将bean代理对象直接依赖注入,从而打破循环,直接实例初始化成功
    3.直到用的时候,才会去找容器对应的bean对象的方法
    
  48. 自动装配的基本原理
  49. 定义:自动装配简而言之就是将第三方依赖的bean自动装载到IOC容器里面,不需要开发人员去写bean的配置信息
    
    使用:
    1.引入spring-boot-starter依赖
    2.@SpringBootApplication注解开启功能,这是一个复合注解,实际是@EnableAutoConfiguration注解开启的功能
    
    该功能的实现主要依赖于以下三步:
    1.引入依赖的时候,第三方依赖里面应当包含@Configuration配置类,以@Bean注解的方式声明
    2.这个配置类的的全路径应当写入,classpath:/META-INF/spring.factories,这个文件里面[默认情况下,一般官方组件已经完成这步骤了,有需要的话,就要自己修改],SpringFactoriesLoader加载这个文件以后,spring就知道了对应的bean在哪里了。
    3.知道bean在哪里以后,ImportSelector 接口就能动态加载这些bean。
    
  50. @Resource与@autowired的区别
  51. 两个注解都可以用于声明bean对象
    @autowired
    类型:可以
    名称:必须搭配@qualified注解同时使用
    
    @Resource
    类型:可以
    名称:可以
    
  52. SpringBoot中约定优于配置的理解
  53. 解释:约定大于配置,是一种开发理念,核心思想是让开发人员减少对配置项的维护,从而聚焦于业务逻辑
    
    spring boot如何体现:
    spring boot本身就是这个理念的产物,它类似于一个脚手架,方便开发人员快速spring生态下的应用程序
    
    1.jar包依赖管理
    2.自动装配机制中的第三方组件集成
    3.应用部署到容器
    4.默认加载application配置文件
    
  54. ResponseBody的作用
  55. 声明 将接口方法的返回值转成JSON字符串 并输出
    
    原先没有该注解 仅返回给前端数据 数据由前端界面接收
    有了该注解 会将返回值转成JSON字符串 并放入一个模板HTML的body里面 从而输出到浏览器
    
  56. Controller与RestController的区别?
  57. ``` RestController=Controller+responseBody ```
posted @ 2023-07-07 21:47  356a  阅读(152)  评论(0编辑  收藏  举报