Spring 面试题整理,springboot 视频教程谁的好
首先说一下 Servlet 的生命周期:实例化,初始化 init,接收请求 service,销毁 destroy;
Spring 上下文中的 Bean 声明周期也类似,如下:
(1)实例化 Bean
对于 BeanFactory 容器,当用户向容器请求一个尚未初始化的 bean 时,或初始化 bean 的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean 进行实例化。
对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 bean。
(2)设置对象属性(依赖注入)
实例化后的对象被封装在 BeanWrapper 对象中,紧接着,Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入。
(3)处理 Aware 接口
Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 Bean;
① 如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String beanId)方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
② 如果这个 Bean 已经实现了 BeanFatoryAware 接口,会调用它实现的 setBeanFactory()方法,传递的是 Spring 工厂本身;
③ 如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用它实现的 setApplicationContext(ApplicationContext)方法,传入 Spring 上下文;
(4)BeanPostProcessor
如果想对 Bean 进行一些自定义的处理,那么可以让 Bean 实现了 BeanPostProcessor 接口,那将会调用 postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean?与?init-method
如果 Bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)实现 BeanPostProcessor 接口
如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用 postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在 Bean 初始化结束时调用的,所以可以被应用于内存或缓存技术;
(7)DisposableBean
当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy()方法;
(8)destroy-method
最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。
7、解释 Spring 支持的几种 bean 的作用域
Spring 容器中的 bean 可以分为 5 个范围:
(1)singleton:默认,每个容器只有一个 bean 的实例,单例的模式由 BeanFactory 自身来维护;
(2)prototype:为每一个 bean 请求提供一个实例;
(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean 会失效并被垃圾回收器回收;
(4)session:与 request 范围类似,确保每个 session 中有一个 bean 的实例,在 session 过期后,bean 会随之失效。
(5)global-session:全局作用域,global-session 与 Portlet 应用相关。当你的应用部署在 Portlet 容器中工作时,它包含很多 portlet。如果你想要的声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在 global-session 中。全局作用域与 servlet 中的 session 作用域效果相同。
portlet 是基于 Java 的 web 组件,由 Portlet 容器管理,并由容器处理请求,生成动态内容。
使用 portlet 作为可插拔用户接口组件,提供信息系统的表示层。
作为利用 servlets 进行 web 应用编程的下一步,portlet 实现了 web 应用的模块化和用户中心化。
8、Spring 框架中的单例 Bean 是线程安全的吗?
Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。
但实际上,大部分的 Spring bean 并没有可变的状态(比如 service 和 dao),所以在某种程度上说 Spring 的单例 bean 时线程安全的。如果你的 bean 有多种状态的话(比如 view model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态 bean 的作用域由 singleton 改为 prototype。
9、Spring 如何处理线程并发问题?
在一般情况下,只有无状态的 Bean 才可以在多线程环境下共享,在 Spring 中,绝大部分 Bean 都可以声明为 singleton 作用域,因为 Spring 对于一些 Bean 中非线程安全状态采取 ThreadLocal 进行处理,解决线程安全问题。
ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。
ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进 ThreadLocal。
10、Spring 的自动装配
在 Spring 框架 xml 配置中共有 5 种自动装配:
(1)no:默认的方式是不进行自动装配的,通过手工 ref 属性来进行装配 bean。
(2)byName:通过 bean 的名称进行自动装配,如果一个 bean 的 property 与另一 bean 的 name 相同,就进行自动装配。
(3)byType:通过参数的数据类型进行自动装配。
(4)constructor:利用构造函数进行装配,并且构造函数的参数通过 byType 进行装配。
(5)autodetect:自动探测,如果有构造函数,通过 construct 的方式自动装配,否者使用 byType 的方式自动装配。
基于注解的方式:
使用 @Autowired 注解来自动装配指定的 bean。在使用 @Autowired 注解之前需要在 Spring 配置文件进行配置,<context:annotation-config />。
在启动 spring IOC 时,容器自动装载一个 AutowiredAnnotationBeanPostProcessor 后置处理器,当容器扫描到 @Autowired、@Resource 或 @Inject 时,就会在 IOC 容器自动查找需要的 bean,并装配给该对象的属性。在使用 @Autowired 时,首先在容器中查询对应类型的 bean:
如果查询结果刚好为一个,就将该 bean 装配给 @Autowired 指定的数据;
如果查询的结果不止一个,那么 @Autowired 会根据名称来查找;
如果上述查找的结果为空,那么就会抛出异常。解决办法是,使用 required=false。
@Autowired 可用于构造函数、成员变量、setter 方法
@Autowired 和 @Resource 之间的区别?
(1)@Autowired 默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置 required=false)。
(2)@Source 默认是按照名称来装配注入的,只有当找不到与名称匹配的 bean 时才会按照类型来装配注入。
11、Spring 框架中都用到了哪些设计模式?
(1)单例模式:Bean 默认为单例模式,singleton。
(2)工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例。
(3)代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术。
(4)模板方法:用来解决代码重复的问题,比如 TestTemplate、JmsTemplate、JpaTemplate。
(5)观察者模式:定义一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被动更新,如 Spring 中 listener 的实现-->ApplicationListener。
12、Spring 事务有什么用?
事务就是对一系列的数据库操作进行统一的提交和回滚的操作,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作。
这样可以防止出现脏数据,防止数据库数据出现问题。
在 JDBC 中是通过 Connection 对象进行事务管理的,默认是自动提交事务,可以手工将自动提交关闭,通过 commit 方法进行提交,rollback 方法进行回滚,如果不提交,则数据不会真正的插入到数据库中。
hibernate 是通过 Transaction 进行实物管理,处理方法与 JDBC 中类似。
13、Spring 事务的种类
(1)编程式事务管理;
使用 TransactionTemplate。
(2)声明式事务管理;
其本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织在拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行目标方法治好根据执行情况提交或回滚事务。
? ? ? ? 声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过 @Transactional 注解的方式,便可以将事务规则应用到业务逻辑中。
? ? ? ? 声明式事务管理要优于编程式事务管理;唯一不足的地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样作用到代码块级别。
14、Spring 事务的传播行为
Spring 事务的传播行为指的是,当多个事务同时存在的时候,spring 如何处理这些事务的行为。
(1)PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
(2)PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
(3)PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
(4)PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
(5)PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
(6)PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
(7)PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行。
15、Spring 中的隔离级别
(1)?ISOLATION_DEFAULT:这是个?PlatfromTransactionManager?默认的隔离级别,使用数据库默认的事务隔离级别。
评论