1. 什么是 Spring 框架?
Spring 是一种轻量级开发框架,旨在进步开发人员的开发效率以及零碎的可维护性。Spring 官网:https://spring.io/。
咱们个别说 Spring 框架指的都是 Spring Framework,它是很多模块的汇合,应用这些模块能够很不便地帮助咱们进行开发。这些模块是:外围容器、数据拜访 / 集成,、Web、AOP(面向切面编程)、工具、音讯和测试模块。比方:Core Container 中的 Core 组件是 Spring 所有组件的外围,Beans 组件和 Context 组件是实现 IOC 和依赖注入的根底,AOP 组件用来实现面向切面编程。
Spring 官网列出的 Spring 的 6 个特色:
- 核心技术:依赖注入(DI),AOP,事件(events),资源,i18n,验证,数据绑定,类型转换,SpEL。
- 测试:模仿对象,TestContext 框架,Spring MVC 测试,WebTestClient。
- 数据拜访:事务,DAO 反对,JDBC,ORM,编组 XML。
- Web 反对 : Spring MVC 和 Spring WebFlux Web 框架。
- 集成:近程解决,JMS,JCA,JMX,电子邮件,工作,调度,缓存。
- 语言:Kotlin,Groovy,动静语言。
2. 列举一些重要的 Spring 模块?
下图对应的是 Spring4.x 版本。目前最新的 5.x 版本中 Web 模块的 Portlet 组件曾经被废除掉,同时减少了用于异步响应式解决的 WebFlux 组件。
- Spring Core: 根底, 能够说 Spring 其余所有的性能都须要依赖于该类库。次要提供 IoC 依赖注入性能。
- Spring Aspects:该模块为与 AspectJ 的集成提供反对。
- Spring AOP:提供了面向切面的编程实现。
- Spring JDBC : Java 数据库连贯。
- Spring JMS:Java 音讯服务。
- Spring ORM : 用于反对 Hibernate 等 ORM 工具。
- Spring Web : 为创立 Web 应用程序提供反对。
- Spring Test : 提供了对 JUnit 和 TestNG 测试的反对。
3. @RestController vs @Controller
Controller
返回一个页面
独自应用 @Controller
不加 @ResponseBody
的话个别应用在要返回一个视图的状况,这种状况属于比拟传统的 Spring MVC 的利用,对应于前后端不拆散的状况。
@RestController
返回 JSON 或 XML 模式数据
但 @RestController
只返回对象,对象数据间接以 JSON 或 XML 模式写入 HTTP 响应 (Response) 中,这种状况属于 RESTful Web 服务,这也是目前日常开发所接触的最罕用的状况(前后端拆散)。
@Controller +@ResponseBody
返回 JSON 或 XML 模式数据
如果你须要在 Spring4 之前开发 RESTful Web 服务的话,你须要应用 @Controller
并联合@ResponseBody
注解,也就是说@Controller
+@ResponseBody
= @RestController
(Spring 4 之后新加的注解)。
@ResponseBody
注解的作用是将Controller
的办法返回的对象通过适当的转换器转换为指定的格局之后,写入到 HTTP 响应 (Response) 对象的 body 中,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的状况比拟多。
Reference:
- https://dzone.com/articles/spring-framework-restcontroller-vs-controller(图片起源)
- https://javarevisited.blogspot.com/2017/08/difference-between-restcontroller-and-controller-annotations-spring-mvc-rest.html?m=1
4. Spring IOC & AOP
4.1 谈谈本人对于 Spring IoC 和 AOP 的了解
IoC
IoC(Inverse of Control: 管制反转)是一种 设计思维 ,就是 将本来在程序中手动创建对象的控制权,交由 Spring 框架来治理。 IoC 在其余语言中也有利用,并非 Spring 特有。IoC 容器是 Spring 用来实现 IoC 的载体,IoC 容器实际上就是个 Map(key,value),Map 中寄存的是各种对象。
将对象之间的相互依赖关系交给 IoC 容器来治理,并由 IoC 容器实现对象的注入。这样能够很大水平上简化利用的开发,把利用从简单的依赖关系中解放出来。IoC 容器就像是一个工厂一样,当咱们须要创立一个对象的时候,只须要配置好配置文件 / 注解即可,齐全不必思考对象是如何被创立进去的。 在理论我的项目中一个 Service 类可能有几百甚至上千个类作为它的底层,如果咱们须要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只须要配置好,而后在须要的中央援用就行了,这大大增加了我的项目的可维护性且升高了开发难度。
Spring 时代咱们个别通过 XML 文件来配置 Bean,起初开发人员感觉 XML 文件来配置不太好,于是 SpringBoot 注解配置就缓缓开始流行起来。
举荐浏览:https://www.zhihu.com/question/23277575/answer/169698662
Spring IoC 的初始化过程:
IoC 源码浏览
- https://javadoop.com/post/spring-ioc
AOP
AOP(Aspect-Oriented Programming: 面向切面编程)可能将那些与业务无关,却为业务模块所独特调用的逻辑或责任(例如事务处理、日志治理、权限管制等)封装起来 ,便于 缩小零碎的反复代码 , 升高模块间的耦合度 ,并 有利于将来的可拓展性和可维护性。
Spring AOP 就是基于动静代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会应用JDK Proxy,去创立代理对象,而对于没有实现接口的对象,就无奈应用 JDK Proxy 去进行代理了,这时候 Spring AOP 会应用Cglib,这时候 Spring AOP 会应用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:
当然你也能够应用 AspectJ ,Spring AOP 曾经集成了 AspectJ,AspectJ 应该算的上是 Java 生态系统中最残缺的 AOP 框架了。
应用 AOP 之后咱们能够把一些通用性能形象进去,在须要用到的中央间接应用即可,这样大大简化了代码量。咱们须要减少新性能时也不便,这样也进步了零碎扩展性。日志性能、事务管理等等场景都用到了 AOP。
4.2 Spring AOP 和 AspectJ AOP 有什么区别?
Spring AOP 属于运行时加强,而 AspectJ 是编译时加强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
Spring AOP 曾经集成了 AspectJ,AspectJ 应该算的上是 Java 生态系统中最残缺的 AOP 框架了。AspectJ 相比于 Spring AOP 性能更加弱小,然而 Spring AOP 相对来说更简略,
如果咱们的切面比拟少,那么两者性能差别不大。然而,当切面太多的话,最好抉择 AspectJ,它比 Spring AOP 快很多。
5. Spring bean
5.1 Spring 中的 bean 的作用域有哪些?
- singleton : 惟一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次申请都会创立一个新的 bean 实例。
- request : 每一次 HTTP 申请都会产生一个新的 bean,该 bean 仅在以后 HTTP request 内无效。
- session : 每一次 HTTP 申请都会产生一个新的 bean,该 bean 仅在以后 HTTP session 内无效。
- global-session:全局 session 作用域,仅仅在基于 portlet 的 web 利用中才有意义,Spring5 曾经没有了。Portlet 是可能生成语义代码 (例如:HTML) 片段的小型 Java Web 插件。它们基于 portlet 容器,能够像 servlet 一样解决 HTTP 申请。然而,与 servlet 不同,每个 portlet 都有不同的会话
5.2 Spring 中的单例 bean 的线程平安问题理解吗?
大部分时候咱们并没有在零碎中应用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,次要是因为当多个线程操作同一个对象的时候,对这个对象的非动态成员变量的写操作会存在线程平安问题。
常见的有两种解决办法:
- 在 Bean 对象中尽量避免定义可变的成员变量(不太事实)。
- 在类中定义一个 ThreadLocal 成员变量,将须要的可变成员变量保留在 ThreadLocal 中(举荐的一种形式)。
5.3 @Component 和 @Bean 的区别是什么?
- 作用对象不同:
@Component
注解作用于类,而@Bean
注解作用于办法。 @Component
通常是通过类门路扫描来主动侦测以及主动拆卸到 Spring 容器中(咱们能够应用@ComponentScan
注解定义要扫描的门路从中找出标识了须要拆卸的类主动拆卸到 Spring 的 bean 容器中)。@Bean
注解通常是咱们在标有该注解的办法中定义产生这个 bean,@Bean
通知了 Spring 这是某个类的示例,当我须要用它的时候还给我。@Bean
注解比Component
注解的自定义性更强,而且很多中央咱们只能通过@Bean
注解来注册 bean。比方当咱们援用第三方库中的类须要拆卸到Spring
容器时,则只能通过@Bean
来实现。
@Bean
注解应用示例:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {return new TransferServiceImpl();
}
}
下面的代码相当于上面的 xml 配置
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
上面这个例子是通过 @Component
无奈实现的。
@Bean
public OneService getService(status) {case (status) {
when 1:
return new serviceImpl1();
when 2:
return new serviceImpl2();
when 3:
return new serviceImpl3();}
}
5.4 将一个类申明为 Spring 的 bean 的注解有哪些?
咱们个别应用 @Autowired
注解主动拆卸 bean,要想把类标识成可用于 @Autowired
注解主动拆卸的 bean 的类, 采纳以下注解可实现:
@Component
:通用的注解,可标注任意类为Spring
组件。如果一个 Bean 不晓得属于哪个层,能够应用@Component
注解标注。@Repository
: 对应长久层即 Dao 层,次要用于数据库相干操作。@Service
: 对应服务层,次要波及一些简单的逻辑,须要用到 Dao 层。@Controller
: 对应 Spring MVC 管制层,次要用于承受用户申请并调用 Service 层返回数据给前端页面。
5.5 Spring 中的 bean 生命周期?
这部分网上有很多文章都讲到了,上面的内容整顿自:https://yemengying.com/2016/07/14/spring-bean-life-cycle/,除了这篇文章,再举荐一篇很不错的文章:https://www.cnblogs.com/zrtqsk/p/3735273.html。
- Bean 容器找到配置文件中 Spring Bean 的定义。
- Bean 容器利用 Java Reflection API 创立一个 Bean 的实例。
- 如果波及到一些属性值 利用
set()
办法设置一些属性值。 - 如果 Bean 实现了
BeanNameAware
接口,调用setBeanName()
办法,传入 Bean 的名字。 - 如果 Bean 实现了
BeanClassLoaderAware
接口,调用setBeanClassLoader()
办法,传入ClassLoader
对象的实例。 - 与下面的相似,如果实现了其余
*.Aware
接口,就调用相应的办法。 - 如果有和加载这个 Bean 的 Spring 容器相干的
BeanPostProcessor
对象,执行postProcessBeforeInitialization()
办法 - 如果 Bean 实现了
InitializingBean
接口,执行afterPropertiesSet()
办法。 - 如果 Bean 在配置文件中的定义蕴含 init-method 属性,执行指定的办法。
- 如果有和加载这个 Bean 的 Spring 容器相干的
BeanPostProcessor
对象,执行postProcessAfterInitialization()
办法 - 当要销毁 Bean 的时候,如果 Bean 实现了
DisposableBean
接口,执行destroy()
办法。 - 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义蕴含 destroy-method 属性,执行指定的办法。
图示:
与之比拟相似的中文版本:
6. Spring MVC
6.1 说说本人对于 Spring MVC 理解?
谈到这个问题,咱们不得不提提之前 Model1 和 Model2 这两个没有 Spring MVC 的时代。
- Model1 时代 : 很多学 Java 后端比拟晚的敌人可能并没有接触过 Model1 模式下的 JavaWeb 利用开发。在 Model1 模式下,整个 Web 利用简直全副用 JSP 页面组成,只用大量的 JavaBean 来解决数据库连贯、拜访等操作。这个模式下 JSP 既是管制层又是体现层。不言而喻,这种模式存在很多问题。比方①将管制逻辑和体现逻辑混淆在一起,导致代码重用率极低;②前端和后端相互依赖,难以进行测试并且开发效率极低;
- Model2 时代:学过 Servlet 并做过相干 Demo 的敌人应该理解“Java Bean(Model)+ JSP(View,)+Servlet(Controller)”这种开发模式, 这就是晚期的 JavaWeb MVC 开发模式。Model: 零碎波及的数据,也就是 dao 和 bean。View:展现模型中的数据,只是用来展现。Controller:解决用户申请都发送给,返回数据给 JSP 并展现给用户。
Model2 模式下还存在很多问题,Model2 的形象和封装水平还远远不够,应用 Model2 进行开发时不可避免地会反复造轮子,这就大大降低了程序的可维护性和复用性。于是很多 JavaWeb 开发相干的 MVC 框架应运而生比方 Struts2,然而 Struts2 比拟轻便。随着 Spring 轻量级开发框架的风行,Spring 生态圈呈现了 Spring MVC 框架,Spring MVC 是以后最优良的 MVC 框架。相比于 Struts2,Spring MVC 应用更加简略和不便,开发效率更高,并且 Spring MVC 运行速度更快。
MVC 是一种设计模式,Spring MVC 是一款很优良的 MVC 框架。Spring MVC 能够帮忙咱们进行更简洁的 Web 层的开发,并且它天生与 Spring 框架集成。Spring MVC 下咱们个别把后端我的项目分为 Service 层(解决业务)、Dao 层(数据库操作)、Entity 层(实体类)、Controller 层(管制层,返回数据给前台页面)。
Spring MVC 的简略原理图如下:
6.2 SpringMVC 工作原理理解吗?
原理如下图所示:
上图的一个笔误的小问题:Spring MVC 的入口函数也就是前端控制器 DispatcherServlet
的作用是接管申请,响应后果。
流程阐明(重要):
- 客户端(浏览器)发送申请,间接申请到
DispatcherServlet
。 DispatcherServlet
依据申请信息调用HandlerMapping
,解析申请对应的Handler
。- 解析到对应的
Handler
(也就是咱们平时说的Controller
控制器)后,开始由HandlerAdapter
适配器解决。 HandlerAdapter
会依据Handler
来调用真正的处理器来解决申请,并解决相应的业务逻辑。- 处理器解决完业务后,会返回一个
ModelAndView
对象,Model
是返回的数据对象,View
是个逻辑上的View
。 ViewResolver
会依据逻辑View
查找理论的View
。DispaterServlet
把返回的Model
传给View
(视图渲染)。- 把
View
返回给请求者(浏览器)
7. Spring 框架中用到了哪些设计模式?
对于上面一些设计模式的具体介绍,能够看笔主前段时间的原创文章《面试官:“谈谈 Spring 中都用到了那些设计模式?”。》。
- 工厂设计模式 : Spring 应用工厂模式通过
BeanFactory
、ApplicationContext
创立 bean 对象。 - 代理设计模式 : Spring AOP 性能的实现。
- 单例设计模式 : Spring 中的 Bean 默认都是单例的。
- 模板办法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就应用到了模板模式。 - 包装器设计模式 : 咱们的我的项目须要连贯多个数据库,而且不同的客户在每次拜访中依据须要会去拜访不同的数据库。这种模式让咱们能够依据客户的需要可能动静切换不同的数据源。
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个利用。
- 适配器模式 :Spring AOP 的加强或告诉(Advice) 应用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
。 - ……
8. Spring 事务
8.1 Spring 治理事务的形式有几种?
- 编程式事务,在代码中硬编码。(不举荐应用)
- 申明式事务,在配置文件中配置(举荐应用)
申明式事务又分为两种:
- 基于 XML 的申明式事务
- 基于注解的申明式事务
8.2 Spring 事务中的隔离级别有哪几种?
TransactionDefinition 接口中定义了五个示意隔离级别的常量:
- TransactionDefinition.ISOLATION_DEFAULT: 应用后端数据库默认的隔离级别,Mysql 默认采纳的 REPEATABLE_READ 隔离级别 Oracle 默认采纳的 READ_COMMITTED 隔离级别.
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,容许读取尚未提交的数据变更,可能会导致脏读、幻读或不可反复读
- TransactionDefinition.ISOLATION_READ_COMMITTED: 容许读取并发事务曾经提交的数据,能够阻止脏读,然而幻读或不可反复读仍有可能产生
- TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的屡次读取后果都是统一的,除非数据是被自身事务本人所批改,能够阻止脏读和不可反复读,但幻读仍有可能产生。
- TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,齐全遵从 ACID 的隔离级别。所有的事务顺次一一执行,这样事务之间就齐全不可能产生烦扰,也就是说,该级别能够避免脏读、不可反复读以及幻读。然而这将重大影响程序的性能。通常状况下也不会用到该级别。
8.3 Spring 事务中哪几种事务流传行为?
反对以后事务的状况:
- TransactionDefinition.PROPAGATION_REQUIRED: 如果以后存在事务,则退出该事务;如果以后没有事务,则创立一个新的事务。
- TransactionDefinition.PROPAGATION_SUPPORTS: 如果以后存在事务,则退出该事务;如果以后没有事务,则以非事务的形式持续运行。
- TransactionDefinition.PROPAGATION_MANDATORY: 如果以后存在事务,则退出该事务;如果以后没有事务,则抛出异样。(mandatory:强制性)
不反对以后事务的状况:
- TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创立一个新的事务,如果以后存在事务,则把以后事务挂起。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务形式运行,如果以后存在事务,则把以后事务挂起。
- TransactionDefinition.PROPAGATION_NEVER: 以非事务形式运行,如果以后存在事务,则抛出异样。
其余状况:
- TransactionDefinition.PROPAGATION_NESTED: 如果以后存在事务,则创立一个事务作为以后事务的嵌套事务来运行;如果以后没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED。
8.4 @Transactional(rollbackFor = Exception.class)注解理解吗?
咱们晓得:Exception 分为运行时异样 RuntimeException 和非运行时异样。事务管理对于企业应用来说是至关重要的,即便出现异常状况,它也能够保证数据的一致性。
当 @Transactional
注解作用于类上时,该类的所有 public 办法将都具备该类型的事务属性,同时,咱们也能够在办法级别应用该标注来笼罩类级别的定义。如果类或者办法加了这个注解,那么这个类外面的办法抛出异样,就会回滚,数据库外面的数据也会回滚。
在 @Transactional
注解中如果不配置 rollbackFor
属性, 那么事务只会在遇到 RuntimeException
的时候才会回滚, 加上rollbackFor=Exception.class
, 能够让事务在遇到非运行时异样时也回滚。
对于 @Transactional
注解举荐浏览的文章:
- 透彻的把握 Spring 中 @transactional 的应用
9. JPA
9.1 如何应用 JPA 在数据库中非长久化一个字段?
如果咱们有有上面一个类:
Entity(name="USER")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private Long id;
@Column(name="USER_NAME")
private String userName;
@Column(name="PASSWORD")
private String password;
private String secrect;
}
如果咱们想让secrect
这个字段不被长久化,也就是不被数据库存储怎么办?咱们能够采纳上面几种办法:
static String transient1; // not persistent because of static
final String transient2 =“Satish”; // not persistent because of final
transient String transient3; // not persistent because of transient
@Transient
String transient4; // not persistent because of @Transient
个别应用前面两种形式比拟多,我集体应用注解的形式比拟多。
参考
- 《Spring 技术底细》
- http://www.cnblogs.com/wmyskxz/p/8820371.html
- https://www.journaldev.com/2696/spring-interview-questions-and-answers
- https://www.edureka.co/blog/interview-questions/spring-interview-questions/
- https://www.cnblogs.com/clwydjgs/p/9317849.html
- https://howtodoinjava.com/interview-questions/top-spring-interview-questions-with-answers/
- http://www.tomaszezula.com/2014/02/09/spring-series-part-5-component-vs-bean/
- https://stackoverflow.com/questions/34172888/difference-between-bean-and-autowired
- 《2020 最新 Java 根底精讲视频教程和学习路线!》