本文是手把手教你锤面试官系列第三篇文章,该系列主要为大家分析和讲解在面试过程中,遇到面试官经常提出的面试问题如何进行攻防。另外本系列的文章也会提供许多小技巧给大家去间接试探出面试官的技术能力和专业水平,从而达到碾压面试官的目的。本系列文章只适用于 JAVA 工程师。
在 JAVAEE 的世界里面 Spring 基本上无所不能,无处不在,基本上除了生孩子以外,可以满足 JAVA 工程师的全套开发需要。Spring 全家桶有多强大,常用的全家桶在下图这张百度来的图片上面可以看出,但其实 spring 还有一些别的比较冷门的工具,如 spring http invoker(微服务未流行的时候的分布式通信框架)、springJdbc、SpringData 等,Spring 还可以整合各种冷门或热门的 MVC 或者 ORM 等框架,如 struts、Mybatis、Hibernate、 JNA、Quartz 等....基本上只有你想不到,没有它整不了的。所以 spring 框架是绕不过去的一个面试必考点,本文我将结合自己多年工作经验给大家梳理一下在面试过程中关于 spring 框架的问题以及回答。
注意:
1.本文只讨论 spring 框架的相关知识,Springmvc,Springboot,SpringCloud 等 Spring 衍生框架不在本文的讨论范围;
2.本文很多的解答是根据本人工作经验总结的个人理解,不一定全对,如有发现错误欢迎留言指正;
3.强烈建议大家花点时间去阅读 Spring 的源代码,本人 2017 年的时候花了差不多两个月的时间根据网上的教程看完了从 githup 上下载下来的 spring3.0 的源代码,受益无穷,不一定需要吃透,只要大概的看一下你就会对设计模式有了质的领悟。
面试官对于 spring 的问题主要有以下几个:
0.spring 是什么东西,干什么用的?
1.spring 的核心 IOC 和 AOP 是用来干嘛的?怎么实现的?
2.spring 加载 Bean 的启动机制和顺序是怎样的?
3.Spring 的 3 个核心组件是哪些,分别用来干啥用的?
4.谈一下在 Spring 中托管的 bean 的作用域和生命周期是怎样的?
5.Spring 中的事务传播和隔离级别有哪些?
0.0 回答
spring 与其说是一个框架不如说是一个容器,表面上看是用来协助程序员管理 Bean。但实际上我个人认为,Spring 这个容器专门内置了一系列的组件和工具来规范设计模式学得不好的程序员简单方便的使用各种设计模式写出高质量的代码。大家可以回忆一下,我们使用 Spring 之后有一个关键字是不是很少见了——new,基本上你用 Spring 管理 Bean 之后,new 是不是消失了(想想 ApplicationContext 的使用)?还有代码的复用性是不是提高了(想想 Service 的使用)?很多在实例化的时候需要进行条件判断进行实例化的判断是不是也少了?Spring 本身就是一套集合了工厂模式、单例模式、原型模式、代理模式合观察者模式一体的优秀框架。所以我们可以说,spring 是一个对 bean 进行托管的容器或者手脚架,作用是给设计模式学得不好的程序员提供一套标准和组件,让他们可以写出更规范标准优质的代码。
1.1 回答
我们常说 Spring 的核心就是两个——IOC(反转控制)和 AOP(面向切面编程)。
IOC 的功能用人话来说就是,我们可以不用通过 new 就可以拿到一个 Bean 的对象(结合我上一篇文章中对涉及模式的梳理来理解)。
spring 的 IOC 实现原理非常简单,就是通过解析注解或者 xml 中的配置拿到这个类的描述信息,通过 JAVA 的反射机制实现不用 new 直接将一个 object 对象转化成目标 Bean 对象。我们弄清楚 IOC 的实现就是反射之后可以结合 dom4j 非常简单的自己动手写一个 IOC 框架,快的话不需要 20 分钟。大概思路如下:启动主类调用 dom4j 去解析某个 xml 里面对 class 的包描述,然后通过反射机制 Class.forName 等方法就可以实例化出来一个对象啦。
AOP,就是所谓的面向切片编程。用人话来说就是我可以在某个 class 字节码文件中的某个方法的前面或者后面,在该方法执行的时候插入一段执行代码。专业的术语描述如下:将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。
Spring 的 AOP 实现原理非常简单,比 IOC 还要简单很多。AOP 是基于代理模式(又是设计模式)实现的,它分为静态代理和动态代理。
静态代理,就是把一个通过 AspectJ 组件在把 AOP 切面中方法所在的 JAVA 文件编译成 class 的时候,会把切入的方法添加到该 java 文件中后再去编译 class。
动态代理,就是 JAVA 文件编译成 class 之后,动态去修改 class 里面切面方法的所在类的内容。
Spring 的动态代理由两种实现方式:
1)通过 JDK 的动态代理既利用接口和反射机制去动态改变一个 class 中的内容。
2)利用 cglib-xxx.jar 包中 Enhancer 工具类,通过追溯目标类父类的方式,通过回调机制去动态修改 class 中的内容。(该段描述可能存疑,可能不是修改,而是另外创建了一个 class。时间太长有可能记错了,也没找到相关资料)
2.2 回答
spring 的启动机制和顺序
看下面三张这张百度来的图片就可以说清楚大概了
1)简单版
2)通用版
3)逼格版(主要是 Spring 生成 Bean 对象的机制和流程)
3.3 回答
spring 的 3 个核心组件如下
Spring Core:核心类库,提供 IOC 服务
Spring Context:提供框架式的 Bean 访问方式(如 BeanFactory,ApplicationContext),以及企业级功能(JNDI、Corn 定时任务等);
Spring AOP:AOP 服务,调用 cglib.jar
4.4 回答
Bean 的生命周期如下
Bean 的作用域如下
Spring IOC 容器创建一个 Bean 实例时,可以为 Bean 指定实例的作用域,作用域包括 singleton(单例模式)、prototype(原型模式)、request(HTTP 请求)、session(会话)、global-session(全局会话)。singleton 是默认的。
5.5 回答
事务传播(@Transactional 注解中配置,如 @Transactional(propagation=Propagation.REQUIRED))
① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的默认设置。
② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘
③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
④ PROPAGATIONREQUIRESNEW:创建新事务,无论当前存不存在事务,都创建新事务。
⑤ PROPAGATIONNOTSUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按 REQUIRED 属性执行
隔离级别(Transactional 注解中配置,如 @Transactional(isolation = Isolation.SERIALIZABLE))
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
② ISOLATIONREADUNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。
③ ISOLATIONREADCOMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。
④ ISOLATIONREPEATABLEREAD:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。
⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。
结束语:
好累,Spring 不愧是企业级 JAVA 的核心,本来想浓缩几个段落就写完的,没想到越写越多一发不可收拾。又到了传授大家小技巧的时候了。想看看一个面试官的 Spring 能力如何,可以问他一个问题——都说 spring 的两大核心是 IOC 和 AOP,为什么依赖注入(DI)不是 Spring 的核心之一呢?不管面试官怎么东拉西扯,解释 DI 为什么不是 spring 的核心都可以判断他的水平非常低。因为答案很简单——DI 就是 IOC,只是叫法不同而已。就像散户和韭菜一样,都是指同一个东西。
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,
,咱们下期见!