Spring知识点脑图

Spring思维脑图 ProcessOn Mind

Spring基本概念

Spring IOC 的理解

IOC (Inverse of Control)控制反转。将之前程序中需要手动创建对象的操作,交由 Spring 框架来实现,创建对象的操作被反转到了 Spring 框架。对象的生命周期由 Spring 来管理,只需要直接从 Spring 那里去获取一个对象。

Spring DI 的理解

DI(Dependency Injection)依赖注入。Spring 框架创建 Bean 对象时,动态的将依赖对象注入到 Bean 组件中,实现依赖对象的注入。

BeanFactory 接口和 ApplicationContext 接口不同点

  1. ApplicationContext 接口继承 BeanFactory 接口,Spring 核心工厂是 BeanFactory,BeanFactory 采取延迟加载,第一次 getBean 时才会初始化 Bean,而ApplicationContext 是会在加载配置文件时初始化 Bean。
  2. ApplicationContext 是对 BeanFactory 扩展,它可以进行国际化处理、 事件传递和 Bean 自动装配以及各种不同应用层的 Context 实现。

开发中基本都在使用 ApplicationContext,Web 项目使 用 WebApplicationContext ,很少用到 BeanFactory。

Spring 核心类以及作用

  • BeanFactory:产生一个新的实例,可以实现单例模式;
  • BeanWrapper:提供统一的 get 及 set 方法;
  • ApplicationContext:提供框架的实现,包括 BeanFactory 的所有功能

Spring 的事务

事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作。这些操作作为一个整体一起向系统提交,要么都执行,要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)。

事务特性:ACID

  • 原子性:事务不可分割 。
  • 一致性:事务执行的前后,数据完整性保持一致 。
  • 隔离性:一个事务执行的时候,不应该受到其他事务的打扰。
  • 持久性:事务一旦结束,数据就永久的保存到数据库。

Spring 中有自己的事务管理机制,使用 TransactionMananger 进行管理,可以通过 Spring 的注入来完成此功能。Spring提供了以下几个事务处理的类:

  1. TransactionDefinition:事务属性定义,定义了事务传播行为类型( 7 种),事务隔离类型( 5 种),超时设置、事务隔离级别、只读、回滚规则)。
  2. TranscationStatus:代表了当前的事务,可以提交、回滚。
  3. PlatformTransactionManager:这个是 Spring 提供的用于管理事务的基础接口。通过这个接口,Spring 可以为如 JDBC、Hibernate 等提供对应的事务管理器,具体的实现就是各个平台来实现。

事务定义样例:

1
2
3
4
5
6
7
TransactionDefinition td = new TransactionDefinition();
TransactionStatus ts = transactionManager.getTransaction(td); try{
//do sth
transactionManager.commit(ts);
}catch(Exception e){
transactionManager.rollback(ts);
}

Spring 的事务实现方式

Spring 事务管理实现方式有两种:编程式事务管理和声明式事务。

编程式事务

使用 TransactionTemplate 或使用底层的 PlatformTransactionManager, 显式的方式调用 beginTransaction() 开启事务、commit() 提交事务、 rollback() 回滚事务,编写代码形式来声明事务,粒度较细,比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚。

声明式事务

底层是建立在 Spring AOP 的基础上,在方法执行前后进行拦截,并在目标方法开始执行前创建新事务或加入一个已存在事务,最后在目标方法执行完后根据情况提交或者回滚事务。

声明式事务的优点:不需要编程,减少了代码的耦合,在配置文件中配置并在目标方法上添加 @Transactional 注解来实现。

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的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

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。

@Transactional(rollbackFor = Exception.class)注解了解吗?

我们知道:Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。

@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

@Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。

Spring AOP

AOP(Aspect Oriented Programming)面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的频率。即通过分离横切关注点来增加程序的模块化。AOP 在不修改现有代码的情况下对现有代码添加功能,这个是 AOP 最重要的能力。

AOP:面向切面编程,允许程序模块化横向切割关注点, 或横切典型的责任划分,如日志和事务管理。

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 快很多。

@Component 和 @Bean 的区别是什么?

  1. 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。
  2. @Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。
  3. @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。

将一个类声明为Spring的 bean 的注解有哪些?

我们一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
  • @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

@RestController vs @Controller

Spring 的通知类型

通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 Spring AOP 框架触发的代码段。

Spring 的通知类型总共有 5 种:前置通知、环绕通知、后置通知、异常通知、 最终通知。

  • 前置通知(Before advice):在目标方法执行之前执行的通知。在某连接点( join point )之前执行的通知,但这个通知不能阻止连接点前的 执行(除非它抛出一个异常)。
  • 环绕通知(Around Advice): 在目标方法执行之前和之后都可以执行额外代码的通知。也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
  • 后置通知(After (finally) advice):目标方法执行之后(某连接点退 出的时候)执行的通知(不论是正常返回还是异常退出)。
  • 异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
  • 最终通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

Spring 通知类型使用场景分别有哪些

通知类型 使用场景
环绕通知 控制事务 权限控制
后置通知 记录日志(方法已经成功调用) 记录日志(方法已经成功调用
异常通知 异常处理 控制事务
最终通知 记录日志(方法已经调用,但不一定成功)

Spring Beans 的理解

  • Spring Beans 是被实例的,组装的及被 Spring 容器管理的 Java 对象;
  • Spring Beans 会被 Spring 容器自动完成 @bean 对象的实例化 ;
  • Spring 框架定义的 Beans 都是默认为单例,也可以配置为多例。

Spring 的优点

  • 提供控制反转能力,将对象的创建交给了 Spring,降低了代码耦合性、 侵入性。
  • Spring 是 POJO 编程,使得可持续构建和可测试能力提高 。
  • Spring 是开源免费的 。
  • 方便集成各种优秀的框架。

Spring 和 Struts 的区别

Spring

  1. 具备 IOC/DI、AOP 等通用能力,提高研发效率 ;
  2. 除了支持 Web 层建设以外,还提供了 J2EE 整体服务 ;
  3. 方便与其他不同技术结合使用,例如:Hibernate,Mybatis 等 ;
  4. Spring 拦截机制是方法级别 。

Struts

  1. 是一个基于 MVC 模式的一个 Web 层的处理器;
  2. Struts 拦截机制是类级别。

Spring 框架组成

主要七大模块:

  1. Spring AOP 面向切面编程
  2. Spring ORM Hibernate|mybatis|JDO
  3. Spring Core 提供 Bean 工厂 IOC
  4. Spring Dao JDBC 支持
  5. Spring Context 提供了关于 UI 支持、邮件支持等
  6. Spring Web 提供了 Web 的一些工具类的支持
  7. Spring MVC 提供了 Web MVC、Webviews、JSP、PDF、Export

BeanFactory 的理解

  • BeanFactory 用于管理 Bean 的,通过 BeanFactory 可以从 Spring 中获取注册到其中的 Bean 来使用。
  • BeanFactory 实现基于工厂模式,提供了控制反转功能,把应用的配置和依赖从真正的应用代码中分离。
  • 最 常 用 的 BeanFactory 实 现 是 XmlBeanFactory 、 XmlWebApplicationContext、ClassPathXmlApplicationContext 等。

Spring 中的 Web 模块

Spring 的 Web 模块是构建在 application context 模块基础之上,提供一个适合 Web 应用的上下文。

这个模块也包括支持多种面向 Web 的任务,如透明地处理多个文件上传请求和程序级请求参数的绑定到你的业务对象。

BeanFactory 和 Application contexts 区别

  1. BeanFactory 提供了最简单的容器功能,只提供了实例化对象和拿对象的功能。
  2. Application contexts 应用上下文,继承 BeanFactory 接口,它是 Spring 的一个更高级的容器,提供了更多有用的功能。

Spring 依赖注入的理解

通常情况下,当需要调用一个其他对象的时候,采用 new 的方式进行对象的创 建,导致对象之间耦合性增强,后续代码维护比较困难。

Spring 框架提供了依赖注入的能力,对象统一由 Spring 容器创建,Spring 容器会负责程序之间的关系。这样控制权由应用代码转移到 Spring 容器,控制权发生了反转,就是 Spring 的控制反转。创建依赖对象的工作交由 Spring 容器来完成,然后注入调用者,这就是依赖注入。

Bean 装配

Spring 容器根据 Bean 之间的依赖关系,将 Bean 通过依赖注入进行组装在一起,这就是 Bean 装配。

Bean 的自动装配

在 Spring 框架里面是使用 配置方式进行依赖注入,如果 Bean 对象较多的情况下注入工作就比较麻烦,XML 文件会变得很难维护,所以为了简化 XML 配置文件,提高开发效率可以使用 @autowire(自动装配),能通过 Bean 工厂自动处理 Bean 之间的协作。

自动装配有几种方式

有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。

  1. no:默认设置,表示没有自动装配,通过显式设置 Bean 引用来进行装配。
  2. byName:根据 Bean 的名称注入对象依赖项。
  3. byType:根据类型注入对象依赖项。
  4. constructor:通过调用类的构造函数来注入依赖项。
  5. autodetect:先尝试 constructor 来自动装配,若不成功,则使用 byType 方式。

基于注解的容器配置

开发者通过在相应的类、方法或属性上使用注解的方式,直接在组件类中进行配置, 而不是使用 XML 表述 Bean 的装配关系。

JdbcTemplate 类的作用

JDBCTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象,执行写好的或可调用的数据库操作语句,提供自定义的数据错误处理。

Aspect 切面

AOP 核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有 一组 API 提供横切功能。比如,一个日志模块可以被称作日志的 AOP 切面。 根据需求的不同,一个应用程序可以有若干切面。在 Spring AOP 中,切面通过带有 @Aspect 注解的类实现。

Spring AOP 中的织入的理解

织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。 织入可以在编译时,加载时,或运行时完成。

说说自己对于 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 的流程

  1. 用户发送请求至前端控制器 DispatcherServlet
  2. DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
  3. 处理器映射器根据请求 url 找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet。
  4. DispatcherServlet 通过 HandlerAdapter 处理器适配器调用处理器
  5. 执行处理器(Controller,也叫后端控制器)。
  6. Controller 执行完成返回 ModelAndView。
  7. HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet。
  8. DispatcherServlet 将 ModelAndView 传给 View Reslover 视图解析器。
  9. View Reslover 解析后返回具体 View。
  10. DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet 响应用户。

Spring 配置文件

Spring 配置文件是个 XML 文件,这个文件包含了类信息,描述了如何配置它们,以及如何相互调用。

@RequestMapping 注解用在类上的作用

用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

把某个请求映射到特定的方法上面

在方法上面加上注解 @RequestMapping,并且在这个注解里面写上要拦截的路径。

Spring 对 DAO 的支持

Spring 提供的 DAO (数据访问对象)支持主要的目的是便于以标准的方式使用不同的数据访问技术。

  • 简化 DAO 组件的开发。Spring 提供了一套抽象 DAO 类供你扩展。这些抽象类提供了一些方法,用来简化代码开发。
  • IOC 容器的使用,提供了 DAO 组件与业务逻辑组件之间的解耦。所有的 DAO 组件,都由容器负责注入到业务逻辑组件中,其业务组件无须关心 DAO 组件的实现。
  • 面向接口编程及 DAO 模式的使用,提高了系统组件之间的解耦,降低 了系统重构的成本。
  • 方便的事务管理:Spring 的声明式事务管理力度是方法级。
  • 异常包 装 : Spring 能够包装 Hibernate 异 常 , 把 它 们 从 CheckedException 变为 RuntimeException;开发者可选择在恰当的 层处理数据中不可恢复的异常,从而避免烦琐的 catch/throw 及异常声明。

Spring事务传播类型

image-20210804195443771

Spring应用场景题

Spring 配置 Bean 实例化的方式

  1. 使用类构造器实例化(默认无参数)
1
<bean id="bean1" class="cn.itcast.spring.b_instance.Bean1"></bean> 
  1. 使用静态工厂方法实例化(简单工厂模式)

下面这段配置的含义:调用 Bean2Factory 的 getBean2 方法得到 bean2 。

1
2
3
<bean id="bean2" class="cn.heu.spring.b_instance.Bean2Factory" 

factorymethod="getBean2"></bean>
  1. 使用实例工厂方法实例化(工厂方法模式)

创建工厂实例 bean3Facory,再通过工厂实例创建目标 bean 实例 。

1
2
3
<bean id="bean3Factory" class="cn.heu.spring.b_instance.Bean3Factory"/>

id="bean3" factorybean="bean3Factory" factorymethod="getBean3"></bean>

Bean 注入属性有哪几种方式

  1. 属性注入方式,通过 setXXX() 方法注入 Bean 的属性值或者依赖对象。

  2. 构造函数注入方式,使用的前提:Bean 必须提供带参的构造函数 。

  3. 工厂方法注入方式 。

Spring 中实现时间处理

在 applicationContext.xml 中配置事件源、监听器,先得到事件源,调用事件源的方法,通知监听器。

**Spring 中更高效的使用 JDBC **

传统的 JDBC 实现有两个不足之处:

  • 连接需要自己管理操作

  • JDBC 操作代码封装与编写重复实现

JdbcTemplate 的优点有:

  1. 配置基于模板化处理

  2. JdbcTemplate 是线程安全类

  3. 实例化操作比较简单,仅需要传递 DataSource

  4. 自动完成资源的创建和释放工作

  5. 对 JDBC 的核心流程进行了封装,简化了对 JDBC 的操作

  6. 创建一次 JdbcTemplate,到处可用,避免重复开发

设计模式在 Spring 框架中的使用

  1. 工厂模式:BeanFactory 就是简单工厂模式的体现,用来创建对象的实例。

  2. 单例模式:Bean 默认为单例模式。

  3. 代理模式:Spring 的 AOP 功能用到了 JDK 的动态代理和 CGLIB 字节码生成技术。

  4. 模板方法:用来解决代码重复的问题。比如:RestTemplate, JmsTemplate, JpaTemplate。

  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如 Spring 中 listener 的实现:ApplicationListener。

Spring 框架的优点

  1. 非侵入式设计:代码与框架的依赖性比较低。

  2. 代码解耦:提供控制反转能力,对象的创建和依赖关系的维护工作都交给 Spring 容器的管理,大大的降低了对象之间的耦合性。

  3. 可复用性提高:支持 AOP ,允许将一些通用能力(打印日志、事务处理、 安全操作等)进行集中式处理。

  4. MVC 框架:Spring 的 Web 框架是个精心设计的框架,是 Web 框架的一个很好的替代品。

  5. 事务支持方便:Spring 提供一个持续的事务管理接口,配置化完成对事务的管理,减少手动编程。

  6. 异常处理:Spring 提供方便的 API 把具体技术相关的异常(比如由 JDBC、Hibernate or JDO 抛出的)转化为一致的 unchecked 异常。

  7. 方便程序测试:提供了对 Junit4 的支持,可以通过注解方便的测试 Spring 程序。

哪种依赖注入方式建议使用,构造器注入,还是 Setter 方法注

两种依赖方式都可以使用,构造器注入和 setter 方法注入。最好的解决方案是用构造器参数实现强制依赖,setter 方法实现可选依赖。

定义类的作用域

可以通过 Bean 定义中的 scope 属性来定义。如,当 Spring 要在需要的时候每次生产一个新的 Bean 实例 , Bean 的 scope 属性被指定 为 prototype。另一方面,一个 Bean 每次使用的时候必须返回同一个实例,这个 Bean 的 scope 属性必须设为 singleton。

Spring 支持的几种 Bean 的作用域

Spring 框架支持以下五种 Bean 的作用域:

  1. singleton:Bean 在每个 Spring IOC 容器中只有一个实例。

  2. prototype:一个 Bean 的定义可以有多个实例。

  3. request:每次 http 请求都会创建一个 Bean,该作用域仅在基于 Web 的 Spring ApplicationContext 情形下有效。

  4. session:在一个 HTTP Session 中,一个 Bean 定义对应一个实例。 该作用域仅在基于 Web 的 Spring ApplicationContext 情形下有效。

  5. global-session:在一个全局的 HTTP Session 中,一个 Bean 定义对 应一个实例。该作用域仅在基于 Web 的 Spring ApplicationContext 情形下有效。

缺省的 Spring Bean 的作用域是 Singleton。

可以在 Spring 中注入一个 null 和一个空字符串吗

可以

Spring 中如何注入一个 Java 集合

Spring 提供以下几种集合的配置元素:

  1. 类型用于注入一列值,允许有相同的值。

  2. 类型用于注入一组值,不允许有相同的值。

  3. 类型用于注入一组键值对,键和值都可以为任意类型。

  4. 类型用于注入一组键值对,键和值都只能为 String 类型。

什么是基于 Java 的 Spring 注解配置? 给一些注解的例子

基于 Java 的配置,允许你在少量的 Java 注解的帮助下,进行你的大部分 Spring 配置而非通过 XML 文件.

以 @Configuration 注解为例,它用来标记类可以当做一个 Bean 的定义,被 Spring IOC 容器使用。另一个例子是 @Bean 注解,它表示此方法将要返回一 个对象,作为一个 Bean 注册进 Spring 应用上下文。

你更倾向用那种事务管理类型

声明式事务管理,因为它对应用代码侵入性很少,更符合一个无侵入的轻量级容器的思想。 声明式事务管理要优于编程式事务管理,虽然比编程式事务管理(这种方式允许 你通过代码控制事务)少了一点灵活性。

Bean 的调用方式有哪些

有三种方式可以得到 Bean 并进行调用。

1. 使用 BeanWrapper

1
2
3
4
5
6
7
HelloWorld hw=new HelloWorld(); 

BeanWrapper bw=new BeanWrapperImpl(hw);

bw.setPropertyvalue(”msg”,”HelloWorld”);

system.out.println(bw.getPropertyCalue(”msg”));

2. 使用 BeanFactory

1
2
3
4
5
6
7
InputStream is=new FileInputStream(”config.xml”);

XmlBeanFactory factory=new XmlBeanFactory(**is**);

HelloWorld hw=(HelloWorld) factory.getBean(”HelloWorld”);

system.out.println(hw.getMsg());

3. 使用 ApplicationConttext

1
2
3
4
5
ApplicationContext actx=new FleSystemXmlApplicationContext(”config.xml”); 

HelloWorld hw=(HelloWorld) actx.getBean(”HelloWorld”);

System.out.println(hw.getMsg());

使用 @ResponseBody 注解。

Spring MVC 里面拦截器是怎么写的

有两种写法,一种是实现接口,另外一种是继承适配器类,然后在 Spring MVC 的配置文件中配置拦截器即可.

当一个方法向 AJAX 返回特殊对象,譬如 Object、List 等,需要做什么处理

加上 @ResponseBody 注解。

如何使用 Spring MVC 完成 JSON 操作

  1. 配置 MappingJacksonHttpMessageConverter

  2. 使用 @RequestBody 注解或 ResponseEntity 作为返回值

Spring MVC 常用的一些注解

  1. @RequestMapping:处理请求地址映射的注解,可用于类或方法上。

  2. @PathVariable:绑定 URI 模板变量值是用来获得请求 url 中的动态参数。

  3. @RequestParam:用于将指定的请求参数赋值给方法中的形参。

  4. @RequestBody:读取 Request 请求的 body 部分数据。

  5. @ResponseBody:用于将 Controller 的方法返回的对象,通过适当的 HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区。

Spring 深度理解

Spring 的生命周期

  • 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 属性,执行指定的方法。
  1. 实例化对象;
  2. 填充属性值及引用;
  3. 调用 BeanNameAwaresetBeanName(String name) 设置 bean 的 id;
  4. 调用 BeanFactoryAwaresetBeanFactory(BeanFactory beanFactory) 设置 BeanFactory Bean工厂;
  5. 同上:ApplicationContextAware``setApplicationContext(ApplicationContext applicationContext)
  6. 如果实现 BeanPostProcessor,则 调用 postProcessBeforeInitialization() 初始化前的后置处理方法;
  7. 如果实现了 InitializingBean 接口,则使用 afterPropertiesSet() 来初始化属性;
  8. 如果实现 BeanPostProcessor,则 调用 postProcessAfterInitialization() 初始化后的后置处理方法;
  9. 此时,bean 就可以使用了;
  10. DisposableBean接口 destroy() 销毁bean。不过在Spring5.0开始,DisposableBean.destroy() 已经是过时的方法了,可直接使用 close()。
image-20210807163127693

Spring 如何处理线程并发问题

Spring 使用 ThreadLocal 解决线程安全问题。

ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程 序设计和编写难度相对较大。

而 ThreadLocal 则从另一个角度来解决多线程的并发访问。 ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。 ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进 ThreadLocal。概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而 ThreadLocal 采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

核心容器(应用上下文)模块的理解

这是基本的 Spring 模块,提供 Spring 框架的基础功能,BeanFactory 是任何以 Spring 为基础的应用的核心。Spring 框架建立在此模块之上,它使Spring 成为一个容器。

为什么说 Spring 是一个容器

Spring 容器是整个 Spring 框架的核心,通常我们说的 Spring 容器就是 Bean 工厂,Bean 工厂负责创建和初始化 Bean、装配 Bean 并且管理应用程序中 的 bean.spring 中 提供了两个核心接 口 — BeanFactory 和 ApplicationContext,ApplicationContext 是 BeanFactory 子接口,它提供了比 BeanFactory 更完善的功能。

Spring 框架中的单例 Beans 是线程安全的么

Spring 框架并没有对单例 Bean 进行任何多线程的封装处理。关于单例 Bean 的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的 Spring Bean 并没有可变的状态(比如 Service 类和 DAO 类),所以在某种程度上说 Spring 的单例 Bean 是线程安全的。如果你的 Bean 有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多 态 Bean 的作用域由“singleton”变为“prototype”。

什么是 Spring 的内部 Bean

当一个 Bean 仅被用作另一个 Bean 的属性时,它能被声明为一个内部 Bean, 为了定义 inner Bean,在 Spring 的基于 XML 的配置元数据中,可以 在 元素内使用 元素,内部 Bean 通常是匿名的,它们的 Scope 一般是 prototype。

自动装配有哪些局限性

  1. 重写: 你仍需用 配置来定义依赖,意味着总要重写自动装配。

  2. 基本数据类型:不能自动装配简单的属性,如基本数据类型、String 字符串和类。

  3. 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。

IOC 的优点是什么

IOC 或依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和 JNDI 查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC 容器支持加载服务时的饿汉式初始化和懒加载。

Spring 框架的事务管理有哪些优点

  1. 它为不同的事务 API 如 JTA、JDBC、Hibernate、JPA 和 JDO,提供一个不变的编程模式。

  2. 它为编程式事务管理提供了一套简单的 API 而不是一些复杂的事务 API。

  3. 它支持声明式事务管理。

  4. 它和 Spring 各种数据访问抽象层很好得集成。

在 Spring AOP 中,关注点和横切关注的区别是什么

  1. 关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。

  2. 横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响 整个应用,比如日志、安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。

Spring AOP 的底层实现原理

Spring AOP 中的动态代理主要有两种方式, JDK 动态代理和 CGLIB 动态代理 。

  • JDK 动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK 动态代理的核心是 InvocationHandler 接口和 Proxy 类。
    1. 创建代理类proxy实现Invocation接口,重写invoke()方法;
    2. 将被代理类作为构造函数的参数传入代理类proxy;
    3. 调用Proxy.newProxyInsatnce(classloader,interfaces,handler)方法生成代理类。
  • 如果目标类没有实现接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类 。CGLIB( Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意, CGLIB 是通 过继承的方式做的动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的 。

如何给 Spring 容器提供配置元数据

  • XML 配置文件

  • 基于注解的配置

  • 基于 Java 的配置

哪些是重要的 Bean 生命周期方法,能重载它们吗

有两个重要的 Bean 生命周期方法,第一个是 setup, 它是在容器加载 Bean 的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。

Bean 标签有两个重要的属性( init-method 和 destroy-method ), 用它们你可以自己定制初始化和注销方法 。

Spring MVC 的控制器是不是单例模式,如果是,有什么问题,怎么解

是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。

Spring 中循环注入的方式

举个列子我有一个类 A,A 有一个构造器里面的参数是类 B,然后类 B 里面有个构造器参数是类 C,类 C 里面有个构造器参数是类 A,就

是我们会发现其实引用循环了 A 里面有 B 的引用,B 里面有 C 的引用,C 里面又有 A 的引用。

当我们用 Spring 来加载 A 的时候 Spring 的流程是这样的(构造器注入):

  1. Spring 创建 A 首先去当前创建池中去查找当前 A 是否在创建,如果发明没有创建则准备其构造器需要的参数 B,然后把创建 A 的标识放入当前创建池中。

  2. Spring 创建 B 首先去当前创建池中去查找当前 B 是否在创建,如果发现没有创建则准备其构造器需要的参数 C,然后把创建 B 的标识放入当前创建池中。

  3. Spring 创建 C 首先去当前创建池中去查找当前 C 是否在创建,如果发现没有创建则准备其构造器需要的参数 A,然后把创建 C 的标识放入当前创建池中。

  4. Spring 创建 C 需要的 A,这个时候会发现在当前创建池中已经有 A 的标识,A 正在创建中则抛出BeanCurrentlyInCreationException。

构造器的循环注入是没有办法解决的,所以只能我们避免。

set 方式的循环注入:

  1. Spring 创建 A,首先根据其无参构造器创建一个对象 A,然后提前暴露出创建出来的这个 A 对象,然后再当前的创建池中放入创建 A 的标识,然后进行 set 方法注入 B。

  2. Spring 创建 B,首先根据其无参构造器创建一个对象 B,然后提前暴露出创建出来的这个 B 对象,然后在当前的创建池中放入创建 B 的标识,然后进行 set 方法的注入 C。

  3. Spring 创建 C,首先根据其无参构造器创建一个对象 C,然后提前暴露出创建处理的这个 C 对象,然后在当前的创建池中放入创建 C 的标识,然后进行 set 方法的注入 A。

  4. 在第三步注入 A 的时候由于提前暴露出来了创建出来的 A 对象所以不会报 BeanCurrentlyInCreationException 的错误。

Spring Boot 相关

什么是 Spring Boot

能够简化 Spring 应用的初始搭建以及开发过程,使用特定的方式来进行配置( properties 或 yml 文件),如:创建独立的 Spring 引用程序 main 方法运行、嵌入的 Tomcat 无需部署 war 文件、 简化 Maven 配置、自动配置 Spring 添加对应功能 starter 自动化配置等。

Spring Boot 自动配置的原理

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

为什么要用 Spring Boot

独立运行、简化配置、自动配置、代码生成和 XML 配置、应用监控、上手容易等

理解 Spring Boot 中的 Starters

Starters 理解为启动器,它包含了一系列可以集成到应用里面的依赖包,方便开发者快速集成 Spring 及其他技术,避免投入很多精力寻找依赖包或者代码的工作。Spring 的官方启动器都是以 spring-boot-starter- 命名的,代表了一个特定的应用类型。

Spring Boot 有哪几种读取配置的方式

Spring Boot 可以通过 @PropertySource、@Value、@Environment、 @ConfigurationProperties 来绑定变量。