引言
在我面试Java开发岗位的时候,曾经遇到过一个让我印象深刻的面试官。他问我很多关于Spring框架的问题,但是我却无法回答其中的一些问题。
当时我感到有些受挫,因为我已经为这个面试做了很多准备,但是还是遇到了一些我没有预料到的问题。我试图回答问题,但是感觉自己的回答并不是很理想。
在面试结束后,我回到家中,开始整理这次面试的问题和我的回答。虽然我没能成功地回答所有问题,但是我还是记录下了一些我认为重要的问题和我自己的思考过程。
通过这个过程,我不仅加深了对Spring框架的理解,还学会了如何应对自己不会的问题。最终,我将这些笔记整理成了一篇博客,分享给了我的朋友们和网络上的开发者们。
这篇博客成为了我的引言,用来叙说我整理的Spring面试题。我希望这篇博客能够帮助更多的开发者在面试中取得成功,同时也能够提高自己的技能水平。
一、Spring IOC篇
1.什么是Spring
Spring 框架是一个分层的、面向切面的 Java 应用程序的一站式轻量级解决方案,它是 Spring 技术栈的核心和基础,是为了解决企业级应用开发的复杂性而创建的。
> 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。介于SpringMVC与Mybatis之间的中间层框架,作用:承上启下,相当于粘合剂
2.核心概念
1)IOC:Inverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。
2)AOP:Aspect Oriented Programming 的简写,译为“面向切面编程”。 AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
3.核心架构
1)**Spring Core**:提供依赖注入和Bean管理功能,主要组件是 `BeanFactory`,它使用控制反转模式将应用程序配置和依赖规范与实际的应用代码分开;
2)**Spring Context**:扩展了`BeanFactory`的概念,增加了对国际化、事件传播,以及验证等的支持,此外还提供了许多企业服务及对模版框架集成的支持;
3)**Spring Web**:建立于Context模块之上,提供了一个适合于Web应用的上下文。另外,这个模块还提供了一些面向服务支持,也提供了Spring和其它Web框架的集成;
4)**Spring Web MVC**:是一个全功能的构建 Web 应用程序的 MVC 实现,容纳了大量视图技术,如 JSP、Velocity、POI等;
5)**Spring AOP**:为Spring容器管理的对象提供了对面向切面编程的支持;
6)**Spring DAO**:该层封装了对数据库的访问,并且处理了其抛出的错误消息,同时还基于AOP模块提供了事务管理;
7)**Spring ORM**(Object Relational Mapping):Spring支持多种ORM框架(Mybatis、Hibernate),简化了数据库操作。
4.什么是控制反转(IOC)
在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。
IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了**主从换位**的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Bean)。
这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。
5.依赖注入(DI)
在面向对象中,对象和对象之间是存在一种叫做“依赖”的关系。简单来说,依赖关系就是在一个对象中需要用到另外一个对象,即对象中存在一个属性,该属性是另外一个类的对象。
控制反转核心思想就是由 Spring 负责对象的创建。在对象创建过程中,Spring 会自动根据依赖关系,将它依赖的对象注入到当前对象中,这就是所谓的“依赖注入”。
> 即由Spring IOC容器动态的将某种依赖关系注入到组件之中
二、Spring AOP篇
1.什么是AOP
AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理、增强处理。
> AOP带来的好处:让我们可以 “专心做事”
2.Spring AOP代理机制
pring 在运行期会为目标对象生成一个动态代理对象,并在代理对象中实现对目标对象的增强。Spring AOP 的底层是通过以下 2 种动态代理机制,为目标对象(Target Bean)执行横向织入的。
- **JDK动态代理:**Spring AOP 默认的动态代理方式,若目标对象实现了若干接口,Spring 使用 JDK 的 java.lang.reflect.Proxy 类进行代理。
- **CGLIB动态代理:**若目标对象没有实现任何接口,Spring 则使用 CGLIB 库生成目标对象的子类,以实现对目标对象的代理。
> 注意:由于被标记为 final 的方法是无法进行覆盖的,因此这类方法不管是通过 JDK 动态代理机制还是 CGLIB 动态代理机制都是无法完成代理的。
3.核心概念
- Joinpoint(连接点)**:指那些被拦截到的点(程序执行过程中明确的点,如方法的调用,或者异常的抛出),在 Spring 中,可以被动态代理拦截目标类的方法。
- **Pointcut(切入点)**:多个连接点的集合,定义了通知应该应用到哪些连接点。
- **Advice(通知)**: 指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。
- **Target(目标)**: 指代理的目标对象。
- **Weaving(植入)**: 指把增强代码应用到目标上,生成代理对象的过程。
- **Proxy(代理)** :指生成的代理对象(将通知应用到目标对象后创建的对象)。
- **Aspect(切面)**:切入点和通知的结合。
4.通知分类
1)前置通知org.springframework.aop.MethodBeforeAdvice在目标方法执行前实施增强。
2)后置通知org.springframework.aop.AfterAdvice在目标方法执行后实施增强。
3)后置返回通知org.springframework.aop.AfterReturningAdvice在目标方法执行完成,并返回一个返回值后实施增强。
4)环绕通知org.aopalliance.intercept.MethodInterceptor在目标方法执行前后实施增强。
5)异常通知org.springframework.aop.ThrowsAdvice在方法抛出异常后实施增强。
6)引入通知org.springframework.aop.IntroductnInterceptor在目标类中添加一些新的方法和属性。
三、Spring MVC篇
1.什么是SpringMVC
Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
2.工作原理
1. 用户发来一个请求,首先进入的是前端控制器DispatcherServlet
2. 前端控制器(DispacherServlet)将用户发来的请求发送给处理器映射器(HandlerMapping)
3. 处理器映射器根据前端控制器发来的用户的请求找到对应符合的控制器(Handler),并且将其封装成处理器执行链,返回给前端控制器。
4. 处理器适配器接收到来自前端控制器的执行链后,找到对应执行此执行链的处理器适配器(HandlerAdapter)来调用的具体的控制器(就是说其对应的方法或者逻辑)
5. 处理器适配器 (HandlerAdaptoer) 会调用对应的具体的 Controller(处理业务逻辑)
6. 控制器执行完成后,会返回一个ModelAndView对象给处理器适配器
7. 处理器适配器将返回来的ModelAndView对象返回给前端控制器(到这里所有的业务处理过程就要完了,接下就是将结果以页面的形式响应给用户)
8. 前端控制器将返回回来的ModelAndView对象交给视图解析器(ViewResolver),视图解析器根据传过来的View对象解析成对应的页面对象
9. ViewResolver 将封装好的页面对象和Model对象返回给 DIspatcherServlet
10. 前端控制器再将返回回来的Model对象交给视图(View)
11. 视图根据传过来的Model对象再一次的对页面进行渲染(将模型数据填充至视图中),然后在返回给前端控制器。
12. 前端控制器将完成的结果响应给浏览器,然后浏览器在展现给用户。
3.核心组件
1)DispatcherServlet是SpringMVC框架了里面的前端控制器
作用:统一处理用户发来的请求和响应,相当于一个中间转换器,减少了各个组件之间的调度,减少的耦合性。
2)HandlerMapping是SpringMVC框架里面的处理器映射器
作用:根据请求发来的url 和method找到对应的Handler(就是说在一个用到SpringMVC框架的项目中会有好多方法和逻辑,这个组件的作用就是找到对应的方法和组件返回给前端控制器)
3)Handler处理器,注意,这个需由工程师自己开发。
作用:在 DispatcherServlet 的控制下,Handler对具体的用户请求进行处理。
4)HandlerAdapter是SpringMVC框架提供的处理器适配器
作用:根据映射器找到的处理器Handler信息,按照特定的规则去执行相关的处理器 Handler。
5)ViewResolver是SpringMVC框架提供的视图解析器
作用:就是字如其名,就是用来将处理的结果解析成视图来展现给用户。视图解析器根据逻辑视图名解析成物理视图名,生成View视图对象,最后对视图进行渲染响应给用户。
6)View是开发者自己提供的视图
作用:根据model对象的要求来渲染页面,然后前端控器在响应给用户。
四、Spring注解篇
1.Spring常用注解
1)@Repository将DAO类声明为Bean
2)@Service用于修饰service层的组件
3)@Controller通常作用在控制层,将在Spring MVC中使用
4)@Component是一个泛化的概念,仅仅表示spring中的一个组件(Bean),可以作用在任何层次
5)@Scope是springIoc容器中的一个作用域,在 Spring IoC 容器中具有以下几种作用域:singleton(单例)、prototype(多例)、Web 作用域(reqeust、session、globalsession)、自定义作用域。
6)@Autowired将自动在Spring上下文与其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方
7)@Resource:
(1)@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)指定了name或者type则根据指定的类型去匹配bean
(3)指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错@Transactional声明式事务管理编程中使用的注解
2.SpringMVC常用注解
1)@RequestMapping:注解是一个用来处理请求地址映射的注解,可用于映射一个请求或一个方法,可以用在类或方法上。
(1)用于方法上,表示在类的父路径下追加方法上注解中的地址将会访问到该方法
(2)用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
2)@RequestParam:主要用于将请求参数区域的数据映射到控制层方法的参数上
3)@ModelAttribute:
(1)绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用;
(2)暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用;
(3)暴露@RequestMapping方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用。
4)@SessionAttributes:在默认情况下,当ModelMap中的属性作用域是request级别时,也就是说,当本次请求结束后,ModelMap中的属性将销毁。如果希望在多个请求中共享ModelMap中的属性,必须将其属性转存到session中,这样ModelMap的属性才会被跨请求访问;
spring允许我们有选择地指定ModelMap中的哪些属性需要转存到session中,以便下一个请求属对应的ModelMap的属性列表中还能访问到这些属性。
SpringMVC为我们提供这样一个注解来实现上面的场景:`@SessionAttributes`:将ModelMap的属性值共享到session中。
5)@RequestBody:主要用来接收前端传递给后端的json字符串中的数据的(即请求体中的数据的);
GET方式无请求体,所以使用@RequestBody接收数据时,**前端不能使用GET方式提交数据,而是用POST方式进行提交**。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
简而言之:
(1) 一个请求:只有一个@RequestBody;
(2) 一个请求:可以有多个@RequestParam。
6)@RequestHeader:使用 @RequestHeader 注解可以获取指定的请求头信息。如果想要获取所有的请求头信息,可以使用 Map<String,String>、MultiValueMap<String,String>、HttpHeaders 这三个 Map 中的任何一个封装所有请求头的 name 和 value。
7)@PathVariable:该注解请求URI中的模板变量部分到处理器功能处理方法的方法参数上的绑定。
即当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable注解绑定它传过来的值到方法的参数上。数上。
8)@CookieValue:注解主要是将请求的Cookie数据,映射到功能处理方法的参数上。