6

JAVA面试题锦集-Spring(SpringMVC)

 2 years ago
source link: http://www.veiking.cn/blog/1076-page.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring的初衷是为了替代EJB,减轻企业应用开发的复杂性。Spring框架是非常轻量的,无论是整个框架的大小还是运行所需开销。此外,Spring是非侵入式的框架,其内部应用依赖的对象并不局限于Spring的特定类,这就令Spring非常友好的和其他的框架一起使用,更容易扩展。Spring通过被叫做控制反转(IOC,Inversion of Control)的技术实现了松耦合

Spring概述

Spring简介:

初衷是为了替代EJB减轻企业应用开发的复杂性,并通过扩展的方式,提供了更多的企业级应用功能。

Spring特点:

Spring框架是非常轻量的,无论是整个框架的大小还是运行所需开销。此外,Spring是非侵入式的框架,其内部应用依赖的对象并不局限于Spring的特定类,这就令Spring非常友好的和其他的框架一起使用,更容易扩展。

Spring之控制反转:

Spring通过被叫做控制反转(IOC,Inversion of Control)的技术实现了松耦合。一般情况下,对象中如果需要依赖其他对象,是需要我们自己主动去创建的,这就造成了程序的耦合度极高。Spring框架通过IOC技术,可以使对象所依赖的对象,以被动的形式传递进来,即不用我们去做操作,而是容器在对象初始化时,就将依赖对象传递给他,这个过程也被称为依赖注入

Spring之切面编程:

面向切面编程(AOP,Aspect-Oriented Programming)又被称为面向方面编程,这个相对于Java强调的面向对象编程(OOP,Object-Oriented Programing),是一种补充和完善。

面向对象编程引入封装、继承和多态性等概念来建立一种对象层次结构,用来描述程序具体业务的集合。当我们需要在这些对象中引入某些公共行为的时候,面向对象编程就显得力不从心。可以这么理解,面向对象编程可以很好的定义从上到下的业务关系,但在横向的公共业务关系上并不擅长。就像日志代码,一般都是散布在对象业务的各个层次中,这个和它所在对象的核心业务并无关系,他只是打个日志。对于其他类似功能的代码,如安全处理、异常处理和一些事务处理也是如此。这种散布在各处与业务无关的功能代码被称为横切代码,这种横向水平分布的结构,我们也可以称之为切面。

在面向切面编程设计实现中,必然会导致了大量横切代码的重复,从而不利于各个功能模块的复用;而面向切面编程则恰恰相反,他通过对这种切面(Aspect,又被译为方面、层面)概念的重塑,剖解开封装的对象内部,并将那些支撑业务类的公共行为封装到一个可重用模块中,从而实现具体业务和支持功能的解耦,这样可以减少系统的重复代码,提高功能模块的复用程度,并对整个系统的可操作性和可维护性有极大的提升

面向切面编程事实上是把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的功能部分是横切关注点。把业务和功能解耦分离,是Spring框架的核心贡献之一,Spring通过面向切面思想,就可以很好的帮我们实现诸如日志、权限、事务等等。

spring 有哪些主要模块

目前Spring框架至今已集成了20多个模块。这些模块主要是Spring-core、Spring-data、Sping-web(SpringMVC)、Spring-test及AOP、Messaging等,具体如下图示:

spring 常用的注入方式有哪些

Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:
a.构造方法注入
b.setter注入
c.基于注解的注入,注解的注入一般说的就是依赖注入。

spring 中的 bean 是线程安全的吗?

Spring容器本身并没有提供Bean的线程安全策略,因此可以说spring容器中的Bean本身不具备线程安全的特性;但是具体还是要结合Bean的特性去研究。

我们知道,bean通常可以分为有状态bean无状态bean
有状态的bean即每个用户最初都会得到一个初始的bean,在用户的生存期内,bean保存了用户的信息,即有状态;一旦用户消失(调用结束或实例结束),bean的生命期也告结束。而无状态bean一旦实例化就被加进会话池中,这个存在跟具体用户没关系,各个用户都可以共用,即使某个用户已经消亡,bean的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。

知道这些即不难理解:有状态bean,是有特定实例变量的对象 ,可以保存数据,是非线程安全的无状态bean,就是没有具体实例变量的对象 .不能保存数据,是不变类,是线程安全的

然后我们再来看Spring,在Spring容器中,我们常用的会话bean根据作用域分主要有两类,即singleton(单例模式)和prototype(原型模式);其中,singleton表示全局只有一个实例,我们可以理解它可以用来服务无状态bean;prototype表示每次被注入的时候,都要重新创建一个实例,可以理解为适合有状态bean。

但是,用singleton模式去使用有状态bean时,可能部分资源会因为共享,发生冲突;而prototype因为每次都创建新的实例,而避免并发线程之间调用相同的资源,就不会出现线程安全的问题。

在Spring的使用中,由于singleton bean能以较少的资源空间承担更多的并发,所以我们也更多倾向于使用singleton bean, 但我们在使用的时候,尽量不要在这个业务流程中设置过多成员变量,避免singleton模式下的使用过程引入有状态bean,如果万不得已必须要用,考虑到线程安全,我们就得必须做相应处理。

Singleton使用过程中,处理成员变量引起线程安全问题的解决方法主要有三个:
1.对于局部变量,用new的方法去实例化
2.使用ThreadLocal解决线程安全问题
3.直接将bean的scope设置为prototype,单例模式走不通,只能用原型模式。

spring 支持几种 bean作用域?

通过spring容器创建Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。

Spring支持以下5种作用域
singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
session:对于每个 Session 会话,使用session定义的Bean将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
globalsession:每个全局的 Session 会话,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。

如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。

spring装配 bean 有哪些方式?

Spring具有强大的灵活性,它提供了三种主要的装配机制
1.隐式的bean发现机制和自动装配
2.在java中进行显示配置
3.在XML中进行显示配置
建议尽可能的使用第一种自动配置的方式,显示配置越少越好。

Spring从两个方面实现自动化装配:
1.组件扫描:也就是告诉spring哪些地方哪些个类中需要spring来创建对象。
2.自动装配:Spring自动满足bean之间的依赖,即依赖注入。

spring 事务实现方式有哪些?

1.编程式事务管理;这个需要我们在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,是相对比较原始的操作
2.基于 TransactionProxyFactoryBean 的声明式事务管理;这个一般需要xml文件配置实现
3.基于 @Transactional 的声明式事务管理
4.基于 Aspectj AOP 配置事务
我们一般在Spring框架使用过程中,尽量借助Aspectj AOP 配置管理事务。

spring 中的事务隔离

这个不仅仅局限于Spring框架,事务隔离指的是不同事务在访问同一资源时,需要做出一定的限制。事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:

脏读:一个事务读到另一个事务未提交的更新数据。
幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。
不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读。

SpringMVC运行流程

SpringMVC具体的工作流程,我们先看下图:

Spring运行流程描述:

1.用户向服务器发送请求,请求被Spring 前置控制器DispatcherServlet拦截;
2.DispatcherServlet对请求URL进行解析。然后根据该URI,调用映射处理器HandlerMapping,获得该请求相关的所有对象(包括处理器对象Handler和与之对应的处理器拦截器HandlerInterceptor),最后一并返回给 DispatcherServlet;
3.DispatcherServlet 再根据获得的Handler,调用处理适配器HandlerAdapter,然后HandlerAdapter去执行Handler,即我们常说的具体业务控制器Controller(又叫后端控制器);
(在运行Controller之前,HttpMessageConveter会根据配置提取Request中的数据并转换成指定的数据,给Controller填充入参)
4.Controller执行完成后,向DispatcherServlet 返回一个ModelAndView对象
5.然后DispatcherServlet 根据返回的ModelAndView,调用视图解析器ViewResolver获取一个视图view
6.接着结合Model和View进行视图渲染,最后将渲染结果响应给客户端;

spring mvc 重要组件

DispatcherServlet:前端控制器,把请求给转发到具体的控制类;
HandlerMapping:映射处理器,负责实现前端控制器请求需要的映射策略;
HandlerAdapter:处理器适配器,是程序更多灵活,易拓展;
Handler:处理器,对,这个就是我们一般需要重点处理的Controller,包含具体的业务逻辑
ModelAndView:服务层返回的数据和视图层的封装类
ViewResolver:视图解析器,解析具体的视图


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK