天天看点

大厂高频面试题-Spring系列AOPIOCBeanFactory和ApplicationContext的区别Bean的生命周期Bean的作用域单例Bean是线程安全的么Spring使用了哪些设计模式及应用场景Spring事务的实现方式原理以及隔离级别Spring事务传播机制Spring事务什么时候会失效Bean的自动装配,有哪些方式SpringBoot自动装配原理如何理解springboot的starter什么是嵌入式服务器,为什么使用嵌入式服务器

大厂高频面试题-Spring系列

  • AOP
  • IOC
  • BeanFactory和ApplicationContext的区别
  • Bean的生命周期
  • Bean的作用域
  • 单例Bean是线程安全的么
  • Spring使用了哪些设计模式及应用场景
    • 简单工厂
    • 工厂方法
    • 单例模式
    • 适配器
    • 装饰器
    • 代理
    • 策略模式
    • 模板模式
  • Spring事务的实现方式原理以及隔离级别
  • Spring事务传播机制
  • Spring事务什么时候会失效
  • Bean的自动装配,有哪些方式
  • SpringBoot自动装配原理
  • 如何理解springboot的starter
  • 什么是嵌入式服务器,为什么使用嵌入式服务器

AOP

当需要为分散的对象引入公共的行为时,OOP显得无力,OOP允许从上到下的关系定义,但是不适合从左到右的。

AOP将程序的交叉业务逻辑封装成一个切面,然后注入到目标对象中,对原有业务功能实现增强。

IOC

容器概念,控制反转,依赖注入。

实际上就是个map,存放着各种对象。

接下来就在代码中需要用到里面对象时再通过DI注入。

BeanFactory和ApplicationContext的区别

ApplicationContext是BeanFactory的子接口,拥有更加完整的功能。

  1. 继承MessageSource,支持国际化
  2. 统一的资源访问方式
  3. 提供在监听器中注册bean的事件
  4. 同时加载多个配置
  5. BeanFactory采用延迟加载的方式注入Bean的,即只有在Bean被使用时,才会对Bean进行实例化,这样就无法发现Spring的配置问题了
  6. ApplicationContext是在容器启动时一次性加载所有的Bean,预加载所有的单例Bean

Bean的生命周期

  1. 解析类得到BeanDefinition
  2. 如果有多个构造方法,则要推断构造方法
  3. 确定好构造方法后,进行实例化得到一个对象
  4. 对对象中的加了@Autowired注解的属性进行属性填充
  5. 回调Aware方法,比如BeanNameAware,BeanFactoryAware
  6. 调用BeanPostProcessor的初始化前的方法
  7. 调用初始化方法
  8. 调用BeanPostProcessor的初始化后的方法,在这里会进行AOP
  9. 如果当前创建的bean是单例的则会把bean放入单例池
  10. 使用bean
  11. Spring容器关闭时调用DisposableBean中destory()方法

Bean的作用域

  1. singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。该对象的生命周期是与Spring IOC容器一致的(但在第一次被注入时才会创建)。
  2. prototype:为每一个bean请求提供一个实例。在每次注入时都会创建一个新的对象
  3. request:bean被定义为在每个HTTP请求中创建一个单例对象,也就是说在单个请求中都会复用这一个单例对象。
  4. session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
  5. application:bean被定义为在ServletContext的生命周期中复用一个单例对象。
  6. websocket:bean被定义为在websocket的生命周期中复用一个单例对象。

单例Bean是线程安全的么

不是线程安全的。

Spring中的Bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。

如果Bean是有状态的 那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作用域 把 "singleton"改为’‘protopyte’ 这样每次请求Bean就相当于是 new Bean() 这样就可以保证线程的安全了。

  1. 有状态就是有数据存储功能
  2. 无状态就是不会保存数据 controller、service和dao层本身并不是线程安全的,只是如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。

Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,Spring的事务管理器

使用Threadlocal为不同线程维护了一套独立的connection副本,保证线程之间不会互相影响(Spring是如何保证事务获取同一个Connection的)

不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。

Spring使用了哪些设计模式及应用场景

简单工厂

由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类

Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。

工厂方法

实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getOjbect()方法的返回值。

单例模式

spring对单例的实现: spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是任意的java对象。

适配器

Spring定义了一个适配接口,使得每一种Controller有一种对应的适配器实现类,让适配器代替Controller执行相应的方法。这样在扩展Controller时,只需要增加一个适配器类就完成了SpringMVC的扩展了。

装饰器

Spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。

代理

动态代理

策略模式

Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring 框架本身大量使用了Resource 接口来访问底层资源。

模板模式

refresh方法

Spring事务的实现方式原理以及隔离级别

在一个方法上加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交,如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚。

针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的rollbackFor属性进行配置,默认情况下会对RuntimeException和Error进行回滚。

注意:

数据库的配置隔离级别是 Read Commited,而Spring配置的隔离级别是 Repeatable Read,请问这时隔离

级别是以哪一个为准?

以Spring配置的为准,如果spring设置的隔离级别数据库不支持,效果取决于数据库

Spring事务传播机制

  1. REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
  2. SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
  3. MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常
  4. REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务
  5. NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务
  6. NEVER:不使用事务,如果当前事务存在,则抛出异常
  7. NESTED:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)

Spring事务什么时候会失效

Sping事务的原理是AOP,那么失效的原因就是这个AOP不起作用了。

常见的有以下几种原因:

  1. 发生了自调用,类里面使用this调用本类的方法,此时this不是代理类,而是对象本身
  2. 方法不是public的,@Transactional只能作用于public方法,否则事务失效,如果非要作用于非public方法,那需要开启AspectJ代理模式
  3. 数据库不支持事务
  4. 没有被Spring管理
  5. 异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)

Bean的自动装配,有哪些方式

field、setter、constructor三种

其中@Autowired默认按照ByType,如果有多个会按照ByName查找,如果同时指定@Qualifier,那么会按照@Qualifier的ByName查找

另外的@Resource,会同时根据name和type指定,如果都没有指定的话会先根据name查找,name找不到会根据type查找

SpringBoot自动装配原理

@Import + @Configuration + Spring spi

自动配置类由各个starter提供,使用@Configuration + @Bean定义配置类,放到METAINF/spring.factories下。

使用Spring spi扫描META-INF/spring.factories下的配置类

使用@Import导入自动配置类

大厂高频面试题-Spring系列AOPIOCBeanFactory和ApplicationContext的区别Bean的生命周期Bean的作用域单例Bean是线程安全的么Spring使用了哪些设计模式及应用场景Spring事务的实现方式原理以及隔离级别Spring事务传播机制Spring事务什么时候会失效Bean的自动装配,有哪些方式SpringBoot自动装配原理如何理解springboot的starter什么是嵌入式服务器,为什么使用嵌入式服务器

如何理解springboot的starter

使用spring + springmvc使用,如果需要引入mybatis等框架,需要到xml中定义mybatis需要的bean

starter就是定义一个starter的jar包,写一个@Configuration配置类、将这些bean定义在里面,然后在starter包的META-INF/spring.factories中写入该配置类,springboot会按照约定来加载该配置类

开发人员只需要将相应的starter包依赖进应用,进行相应的属性配置(使用默认配置时,不需要配置),就可以直接进行代码开发,使用对应的功能了,比如mybatis-spring-boot–starter,springboot-starter-redis

什么是嵌入式服务器,为什么使用嵌入式服务器

节省了下载安装tomcat,应用也不需要再打war包,然后放到webapp目录下面再运行

只需要一个安装了 Java 的虚拟机,就可以直接在上面部署应用程序了

springboot已经内置了tomcat.jar,运行main方法时会去启动tomcat,并利用tomcat的spi机制加载springmvc

继续阅读