面试题个人汇总 - Spring

1. 什么的是bean的自动装配,有哪些方式

Spring 容器能够自动装配相互合作的bean,这意味着容器不需要< constructor-arg >和< property >配置,能通过Bean工厂自动处理bean之间的协作。

开启自动装配,只需要在xml配置文件< bean >中定义“autowire”属性

<bean id = "cutomer" class = "com.xxx.Customer" auowire = "">

auowire属性有5种装配方式:
(一):no - 缺省情况下,自动装配是通过“ref”属性手动设定

手动转配:以value或ref的方式明确指定属性值都是手动装配
需要通过“ref”属性来连接bean

(二):byName - 根据bean的属性名称进行自动装配

Customer的属性名称是person,Spring会将bean id为person的bean通过setter方法进行自动装配
<bean id = "cutomer" class = "com.xxx.Customer" auowire = "byName"/>
<bean id = "person" class = "com.xxx.Person"/>

(三):byType - 根据bean的类型进行自动装配

Customer的属性person的类型为Person,Spring会将Person类型通过setter方法进行自动装配
<bean id = "cutomer" class = "com.xxx.Customer" auowire = "byType"/>
<bean id = "person" class = "com.xxx.Person"/>

(四):constructor - 类似byType,不过是应用于构造器的参数。如果一个bean与构造器参数的类型相同,则进行自动装配,否则导致异常。

Customer的构造函数的参数person的类型为Person,Spring会将Person类型通过构造方法进行自动装配
<bean id = "cutomer" class = "com.xxx.Customer" auowire = "byType"/>
<bean id = "person" class = "com.xxx.Person"/>

(五):autodetect:如果有默认的构造器,则通过constructor 方法进行自动装配,否则使用byType方式进行自动装配

@Autowire自动装配bean,可以在字段,setter方法,构造函数上使用。

2. 如何理解springboot的starter

使用Spring + SpringMVC,如果需要引入mybatis等框架,需要到xml中定义mybatis需要的bean。
starter就是定义一个starter的jar包,写一个@configuration配置类,将这些bean定义在里面,然后在starter包的META-INF/spring.factories中写入该配置类,SpringBoot会按照约定来加载该配置类。

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

3. 如何实现一个IOC容器

  1. 配置文件配置包扫描路径
  2. 递归包扫描获取.class文件
  3. 反射,确定需要交给IOC容器管理的类
  4. 对需要注入的类进行依赖注入
  • 配置文件中指定需要扫描的包路径
  • 定义一些注解,分别表示访问控制层,业务服务层,数据持久层,依赖注入注解,获取配置文件注解
  • 从配置文件中获取需要扫描的包路径,获取到当前路径下的文件信息及文件夹信息,我们将当前路径下所有以.class结尾的文件添加到一个Set集合进行存储
  • 遍历这个Set集合,获取在类上有指定注解的类,并将其交给IOC容器,定义一个安全的Map用来存储这些对象
  • 遍历这个IOC容器,获取到每一个类的实例,判断里面是否有依赖其他类的实例,然后进行递归注入

4. Spring中Bean是线程安全的吗

Spring本身并没有针对Bean做线程安全处理,所以:

  1. 如果Bean是无状态的,那么Bean则是线程安全的
  2. 如果Bean是有状态的,那么Bean则不是线程安全的

另外,Bean是不是线程安全,跟Bean的作用域没有关系,Bean的作用域只是表示Bean的生命周期范围,对于任何生命周期的Bean都是一个对象,这个对象是不是线程安全的,还是得看Bean对象本身。

5. 介绍一下Spring,读过源码介绍一下大致流程

  1. Spring是一个快速开发框架,Spring帮助程序员来管理对象
  2. Spring的源码实现是非常优秀的,设计模式的应用,并发安全的实现,面向接口的设计等
  3. 在创建Spring容器,也就是启动Spring时:
    a :首先会进行扫描,扫描得到所有的BeanDefinition对象,并存在一个Map中
    b: 然后筛选出非懒加载的单例BeanDefinition进行创建Bean,对于多例Bean不需要在启动过程中去进行创建,对于多例Bean会在每次获取Bean时利用BeanDefinition去创建
    c: 利用BeanDefinition创建Bean就是Bean的创建生命周期,这期间包括了合并BeanDefinition,推断构造方法,实例化,属性填充,初始化前,初始化,初始化后等步骤,其中AOP就是发生在初始化后这一步骤
  4. 单例Bean创建完之后,Spring会发布一个容器启动事件
  5. Spring启动结束
  6. 在源码中会更复杂,比如源码中会提供一些模板方法,让子类来实现,比如源码中还涉及到一些BeanFactoryPostProcessor和BeanPostProcessor的注册,Spring的扫描就是通过BeanFactoryPostProcessor来实现的,依赖注入就是通过BeanPostProcessor来实现的
  7. 在Spring启动过程中还会处理@Import等注解

6. 简述spring 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()方法

7. Spring用到了哪些设计模式

  1. 工厂模式:BeanFactory,FactoryBean
  2. 适配器模式:AdvisorAdapter接口,对Advisor进行适配
  3. 访问者模式:PropertyAccessor接口,属性访问器,用来设置和访问某个对象的某个属性
  4. 装饰器模式:BeanWrapper
  5. 代理模式: AOP
  6. 观察者模式:事件监听机制
  7. 策略模式:InstantiationStrategy,根据不同的情况进行实例化
  8. 模板模式:JdbcTemplate
  9. 委派模式:BeanDefinitionParserDelegate
  10. 责任链模式: BeanPostProcessor

8. 说一下Spring的事务机制

  1. Spring事务底层是基于数据库事务和AOP机制的
  2. 首先对于使用了@Transactional注解的Bean,Spring会创建一个代理对象作为Bean
  3. 当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解
  4. 如果加了,那么则利用事务管理器创建一个数据库连接
  5. 并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交,这是实现Spring事务非常重要的一步
  6. 然后执行当前方法,方法中会执行sql
  7. 执行完当前方法后,如果没有出现异常就直接提交事务
  8. 如果出现了异常,并且这个异常想需要回滚的就会回滚事务,否则依然提交事务
  9. Spring事务的隔离级别对应就是数据库的隔离级别
  10. Spring事务的传播机制就是Spring事务自己实现的,也是Spring事务中最复杂的
  11. Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要断开一个事务,那么实际上就是先做一个数据库连接,在此新数据库连接上执行sql

9. 说说常用的SpringBoot注解,及其实现

  • @SpringBootApplication:标识了一个SpringBoot工程,它实际是另外三个注解的组合,这三个注解是:
    a:@SpringBootConfiguration:实际就是一个@Configuration,表示启动类是一个配置类
    b:@EnableAutoConfiguration:想Spring容器中导入了一个Selector,用来加载ClassPath下的SpringFactories中所定义的自动配置类,将这些自动加载为配置bean
    c:@CompoentScan:标识扫描路径,因为默认是没有配置实际扫描路径,所以SpringBoot扫描的路径是启动类所在的当前目录
  • @Bean:用来定义Bean,类似XML中的< bean >标签,Spring在启动时,会对加了@Bean注解的方法进行解析,将方法的名字改为beanName,并通过执行方法得到bean对象

10. 什么时候@Transactional失效

因为Spring事务是基于代理来实现的,所以某个加了@Transactional的方法只有是被代理对象调用时,那么这个注解才会生效的,如果是被代理对象来调用这个方法,那么@Transactional是不会生效的。

同时如果某个方法是private的,那么@Transactional也会失效,因为cglib是基于父子类来实现的,子类是不能重载父类的private方法,所以无法很好的利用代理,也会导致@Transactional失效。

总结:

  • 发生自调用,类里面使用this调用本类的方法,由于这个this对象不是代理类,而是对象本身。
  • 方法不是public的(@Transactional只能用于public方法上,否则事务不会失效,如果非要用在非public方法上,可以开启AspectJ代理模式)
  • 数据库不支持事务
  • 没有被Spring管理
  • 异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)

11. Spring如何处理循环依赖问题

循坏依赖:多个对象之间存在循坏的引用关系,在初始化过程当中,就会出现“先有蛋还是先有鸡的问题”。

一种是使用@Lazy注解:解决构造方法造成的循坏依赖问题

另一种是使用三级缓存:

  1. 一级缓存 : 缓存最终的单例池对象
  2. 二级缓存:缓存初始化对象
  3. 三级缓存:缓存对象动态代理信息

对于对象之间的普通引用,二级缓存会保存new出来的不完整对象,这样当单例池中找到不依赖的属性时,就可以先从二级缓存中获取到不完整对象,完成对象创建,在后续的依赖注入过程中,将单例池对象的引用关系调整完成。

三级缓存:如果引用的对象配置了AOP,那在单例池中最终就会需要注入动态代理对象,而不是原对象,而生成动态代理是要在对象初始化之后才开始的。于是Spring增加三级缓存,保存所有对象的动态代理配置信息。在发现有循坏依赖时,将这个对象的动态代理信息获取出来,提前进行AOP,生成动态代理。

12. Spring中后置处理器的作用

Spring中后置处理器分为BeanFactory后置处理器和Bean后置处理器,它们是Spring底层源码架构设计中非常重要的一种机制,同时开发者也可以利用这两种后置处理器来进行扩展。

BeanFactory后置处理器表示针对BeanFactory的处理器,Spring启动过程中,会先创建出BeanFactory实例,然后利用BeanFactory处理器来加工BeanFactory,比如Spring的扫描就是基于BeanFactory后置处理器来实现的,而Bean后置处理器也类似,Spring在创建一个Bean的过程中,首先会实例化得到一个对象,然后再利用Bean后置处理器来对该实例对象进行加工,比如我们常说的依赖注入就是基于一个Bean后置处理器来实现的,通过该Bean后置处理器来给实例对象加了@Autowired注解的属性自动赋值,还比如我们常说的AOP,也是利用一个Bean后置处理器来实现的,基于原实例对象,判断是否需要进行AOP,如果需要,那么就基于原实例对象进行动态代理,生成一个代理对象。

13. Spring如何处理事务

Spring当中支持编程式事务管理和声明式事务管理:

  1. 编程式事务管理:TransactionTemplate
  2. 声明式事务:Spring在AOP的基础上提供的事务实现机制。最大的优点就是不需要在业务代码中添加事务管理的代码,只需要在配置文件中做相关的事务规则声明就可以了。但是声明式事务只能针对方法级别,无法控制代码级别的事务管理。

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:

  1. PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
  2. PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  3. PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
  4. PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

事务隔离级别:

DEFAULT这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别;

  • 未提交读(read uncommited):脏读,不可重复读,虚读都有可能发生
  • 已提交读(read commited):避免脏读。但是不可重复读和虚读都有可能发生(Oracle默认)
  • 可重复读(repeatable read):避免脏读和不可重复读,但是虚读有可能发生(MySQL默认)
  • 串行化的(serializable):避免以上所有读问题

14. Spring支持的bean作用域

  • singleton : bean 在每个 Spring ioc 容器中只有一个实例
  • prototype:一个 bean 的定义可以有多个实例
  • request:每次 http 请求都会创建一个 bean,该作用域仅在基于 web的 Spring ApplicationContext 情形下有效
  • session:在一个 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效
  • global-session:在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。

缺省的 Spring bean 的作用域是 Singleton(默认情况)

15. Spring框架中Bean的创建过程

简单来说,Spring中的Bean经过了四个阶段:实例化、属性赋值、初始化、销毁

  1. 实例化:当客户端向容器申请一个Bean时;当容器在初始化一个Bean时发现还需要依赖另一个Bean时。都会new一个Bean对象,BeanDefinition对象保存。
  2. 设置对象属性(依赖注入):Spring通过BeanDefinition找到对象依赖的其他对象,并且将这些对象赋予当前对象
  3. 处理Aware接口:Spring会检测对象是否实现xxxAware接口,如果实现了,就会调用对应的方法(BeanNameAware、BeanClassLoaderAware、BeanFactoryAware、ApplicationContentAware)
  4. BeanPostPreocessor前置处理:调用BeanPostPreocessor的postPreocessorBeforeInitialization方法
  5. InitializingBean:Spring检测对象如果实现了这个接口,就会执行它的afterPostPropertiesSet方法,定制初始化逻辑
  6. init-method:< bean init-method = “xxx”> 如果Spring发现Bean配置了这个属性,就会调用它的配置方法,执行初始化逻辑
  7. BeanPostProcessor后置处理:调用BeanPostProcessor的postProcessAfterInitialization方法

到这一步,Bean的创建过程就完成了,Bean可以正常使用。

  1. DisposableBean:当Bean实现了这个接口,在对象销毁前就会调用destory方法
  2. destory-method:< bean destory-method = “xxx”>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值