面试-Spring / Spring MVC

90. 为什么要使用 spring?
91. 解释一下什么是 aop?
92. 解释一下什么是 ioc?
93. spring 有哪些主要模块?
94. spring 常用的注入方式有哪些?
95. spring 中的 bean 是线程安全的吗?
96. spring 支持几种 bean 的作用域?
97. spring 自动装配 bean 有哪些方式?
98. spring 事务实现方式有哪些?
99. 说一下 spring 的事务隔离?
100. 说一下 spring mvc 运行流程?
101. spring mvc 有哪些组件?
102. @RequestMapping 的作用是什么?
103. @Autowired 的作用是什么?

Spring / Spring MVC

90. 为什么要使用 spring?

1.简介

  • 目的:解决企业应用开发的复杂性
  • 功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
  • 范围:任何Java应用

简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

2.轻量  

从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

3.控制反转

Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

4.面向切面  

Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

5.容器

Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

6.框架

Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

91. 解释一下什么是 aop?

AOP(Aspect-Oriented Programming,面向切面编程),通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向切面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

1. AOP相关的概念

1) Aspect :切面,切入系统的一个切面。比如事务管理是一个切面,权限管理也是一个切面;

2) Join point :连接点,也就是可以进行横向切入的位置;

3) Advice :通知,切面在某个连接点执行的操作(分为: Before advice , After returning advice , After throwing advice , After (finally) advice , Around advice );

4) Pointcut :切点,符合切点表达式的连接点,也就是真正被切入的地方;

2. AOP 的实现原理

AOP分为静态AOP和动态AOP。

静态AOP是指AspectJ实现的AOP,他是将切面代码直接编译到Java类文件中。

动态AOP是指将切面代码进行动态织入实现的AOP。

Spring的AOP为动态AOP,实现的技术为: JDK提供的动态代理技术 和 CGLIB(动态字节码增强技术) 。尽管实现技术不一样,但 都是基于代理模式 , 都是生成一个代理对象 。

1) JDK动态代理

主要使用到 InvocationHandler 接口和 Proxy.newProxyInstance() 方法。

 JDK动态代理要求被代理实现一个接口,只有接口中的方法才能够被代理 。

2)CGLIB (code generate libary)

字节码生成技术实现AOP,其实就是继承被代理对象,然后Override需要被代理的方法,在覆盖该方法时,自然是可以插入我们自己的代码的。

因为需要Override被代理对象的方法,所以自然CGLIB技术实现AOP时,就必须要求被代理的方法不能是final方法,因为final方法不能被子类覆盖 。

92. 解释一下什么是 ioc 控制反转?

IOC是Inversion of Control的缩写,多数书籍翻译成"控制反转"

Spring通过DI(依赖注入)实现IOC(控制反转)

简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。

IOC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。如下图:

图 IOC解耦过程

由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。

我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:

图 拿掉IOC容器后的系统

我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系

我们再来看看,控制反转(IOC)到底为什么要起这么个名字?我们来对比一下:

软件系统在没有引入IOC容器之前,如图1所示,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。

软件系统在引入IOC容器之后,这种情形就完全改变了,如图3所示,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方

通过前后的对比,我们不难看出来:对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来

93. spring 有哪些主要模块?

Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。

更多信息:howtodoinjava.com/java-spring-framework-tutorials/

一些重要的Spring Framework模块是:

  • Spring Core: 框架的最基础部分,主要提供 IOC 依赖注入功能,对 bean 进行管理,可以说 Spring 其他所有的功能都需要依赖于该类库。
  • Spring Aspects : 该模块为与AspectJ的集成提供支持。
  • Spring AOP :提供了面向方面的编程实现。
  • Spring JDBC : Java数据库连接。
  • Spring JMS :Java消息服务。
  • Spring ORM : 提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate、MyBatis 等。
  • Spring Web : 为创建Web应用程序提供支持。
  • Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。

94. spring 常用的注入方式有哪些?

简单来说,所谓的依赖注入其实就是,在创建对象的同时或之后,如何给对象的属性赋值。

Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:

  1. 构造方法注入
    采用反射的方式,通过构造方法来完成注入
    如果只有一个有参数的构造方法并且参数类型与注入的bean的类型匹配,那就会注入到该构造方法中
    如果我们想向有多个参数的构造方法中注入值该在配置文件中怎么写呢?通过name属性指定要注入的值,与构造方法参数列表参数的顺序无关
//声明无参构造函数
public User() {
}
//声明有参构造函数
public User(String name, Integer age, UserInfo userInfo) {
    super();
    this.name = name;
    this.age = age;
    this.userInfo = userInfo;
}
  1. setter注入
    要注入的类中必须有 set 方法
    如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错
  2. 基于注解的注入
    主要有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:

    1. @Component:可以用于注册所有bean
    2. @Repository:主要用于注册dao层的bean
    3. @Controller:主要用于注册控制层的bean
    4. @Service:主要用于注册服务层的bean
    5. @Autowired

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

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

96. 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:对于每次HTTP Session,使用session定义的Bean都将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
  • globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

其中比较常用的是singleton和prototype两种作用域。
当把一个 bean 定义设置scope为singleton作用域时,那么Spring IOC容器只会创建该bean定义的唯一实例。也就是说,整个Spring IOC容器中只会创建当前类的唯一一个对象。
这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的、唯一的这个对象实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;
如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会new新建一个Bean实例,然后返回给程序。一旦创建成功,prototype只负责对象的创建和初始化,容器不在跟踪实例,也不会维护Bean实例的状态

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

97. spring 自动装配 bean 有哪些方式?

Spring容器负责创建应用程序中的bean同时通过ID来协调这些对象之间的关系。作为开发人员,我们需要告诉Spring要创建哪些bean并且如何将其装配到一起。

spring中bean装配有两种方式:

  • 隐式的bean发现机制和自动装配
  • 在java代码或者XML中进行显示配置

当然这些方式也可以配合使用。

98. spring 事务实现方式有哪些?

  1. 编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
  2. 基于 TransactionProxyFactoryBean 的声明式事务管理
  3. 基于 @Transactional 的声明式事务管理
  4. 基于 Aspectj AOP 配置事务

99. 说一下 spring 的事务隔离?

事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:

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

100. 说一下 spring mvc 运行流程?

Spring MVC运行流程略图:

image

在MVC设计模式中认为, 任何软件都可以分为三部分组成:

(1)控制程序流转的控制器(Controller
(2)封装数据处理数据的模型(Model
(3)负责展示数据的视图(view

image
Spring运行流程描述:

Springmvc是一个基于mvc的web框架

(1).用户发送请求 至 前端控制器(DispatcherServlet);

提示:前端控制器的作用:接收请求,调用其它组件处理请求,响应结果,相当于转发器、中央处理器,是整个流程控制的中心

(2).前端控制器收到请求后调用处理器映射器(HandlerMapping)

处理器映射器找到具体的Controller(可以根据xml配置、注解进行查找),并将Controller返回给前端控制器;

(3).前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)。

处理器适配器经过适配调用具体的Controller;(Controller--> service --> Dao --> 数据库),Controller执行完成后返回 Model And View,

提示:Model(模型数据,即Controller处理的结果,Map) View (逻辑视图名,即负责展示结果的JSP页面的名字)

处理器适配器(HandlerAdapter)将controller执行的结果(ModelAndView)返回给前端控制器(DispatcherServlet);

(4).前端控制器(DispatcherServlet)将执行的结果(ModelAndView)传给视图解析器(ViewReslover)

视图解析器(ViewReslover)根据View(逻辑视图名)解析后返回具体JSP页面

(5).前端控制器(DispatcherServlet)根据Model对View进行渲染(即将模型数据填充至视图中);

前端控制器(DispatcherServlet)将填充了数据的网页响应给用户。

其中整个过程中需要开发人员编写的部分有ControllerServiceDaoView;

101. spring mvc 有哪些组件?

Spring MVC的核心组件:

  1. 中央处理器(DispatcherServlet),接收请求,调用其它组件处理请求,响应结果
  2. 处理器组件(Controller):具体处理请求的控制器
  3. 处理器映射器(HandlerMapping),负责映射中央处理器转发给controller时的映射策略(是用来查找Handler的,具体接收到一个请求之后使用哪个Handler进行处理)
  4. 处理器适配器(HandlerAdapter):经过适配调用具体的Controller;(Controller--> service --> Dao --> 数据库),Controller执行完成后返回ModelAndView,
  5. ModelAndView:服务层返回的数据和视图层的封装类
  6. 视图解析器(ViewReslover):,根据View(逻辑视图名)解析后返回具体JSP页面
  7. 拦截器(HandlerInterceptor) :,负责拦截我们定义的请求然后做处理工作
  8. 视图组件(View),数据转换组件(DataBinder) ,消息转换器组件(HttpMessageConverter) 等

102. @RequestMapping 的作用是什么?

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

RequestMapping注解有六个属性,下面我们把她分成三类进行说明。

value, method:

  • value:指定请求的实际地址,指定的地址可以是URI Template 模式(后面将会说明);
  • method:指定请求的method类型, GET、POST、PUT、DELETE等;

consumes,produces

  • consumes:指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
  • produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

params,headers

  • params: 指定request中必须包含某些参数值是,才让该方法处理。
  • headers:指定request中必须包含某些指定的header值,才能让该方法处理请求。

103. @Autowired 的作用是什么?

@Autowired是用在JavaBean中的注解,通过byType形式,用来给指定的字段或方法注入所需的外部资源。

@Autowired 可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。

@Autowired 
private UserService userService;

《@Autowired用法详解》:blog.csdn.net/u013257679/article/details/52295106

你可能感兴趣的:(面试,java)