简介

优点:

  • Spring是一个开源免费的框架,容器

  • Spring是一个轻量级的框架,非侵入式的

  • 控制反转 IOC ,面向切面 AOP

  • 对事物的支持,对框架的支持

组成:

  • Spring Core:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

导入Spring框架

maven中央仓库搜索spring直接导入spring-webmvc:

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>

Spring面试题

链接

Spring 里用到了哪些设计模式

单例模式:Spring 中的 Bean 默认情况下都是单例的。无需多说。

工厂模式:工厂模式主要是通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象。

代理模式:最常见的 AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理。

模板方法模式:主要是一些对数据库操作的类用到,比如 JdbcTemplate、JpaTemplate,因为查询数据库的建立连接、执行查询、关闭连接几个过程,非常适用于模板方法。

Bean的生命周期

  1. 实例化,创建一个Bean对象
  2. 填充属性,为属性赋值
  3. 初始化
    • 如果实现了xxxAware接口,通过不同类型的Aware接口拿到Spring容器的资源
    • 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzationpostProcessAfterInitialization方法
    • 如果配置了init-method方法,则会执行init-method配置的方法
  4. 销毁
    • 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy方法
    • 如果配置了destroy-method方法,则会执行destroy-method配置的方法

Bean 的作⽤域

  1. singleton : 唯⼀ bean 实例,Spring 中的 bean 默认都是单例的;

  2. prototype : 每次请求都会创建⼀个新的 bean 实例;

  3. request:每⼀次 HTTP 请求都会产⽣⼀个新的 bean,该 bean 仅在当前 HTTP request 内有效;

  4. session : 每⼀次 HTTP 请求都会产⽣⼀个新的 bean,该 bean 仅在当前 HTTP session 内有效;

Spring 为啥把bean默认设计成单例

  • 减少生成实例的消耗(反射和内存分配)
  • 减少jvm的gc
  • 获取bean迅速(除了第一次,都是从缓存中拿)

缺点:

  • 对象有状态(有属性),并发环境不安全。

单例 Bean 的线程安全问题

多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

  • 不使用非静态成员变量
  • 可变成员变量使用ThreadLocal

Spring是怎么解决循环依赖的

循环依赖:

有两种情况:

  • 两个bean的构造方法同时依赖对方的实例对象
  • 两个bean至少一个对对方的依赖是在setter中的依赖

第一种情况无法解决循环依赖问题

第二种情况的解决办法:三级缓存

  1. A首先实例化,并提前曝光到三级缓存中。然后属性注入,发现依赖B
  2. B开始实例化,属性注入发现依赖A,从三级缓存中取得A,完成初始化,放到一级缓存
  3. A继续初始化,从一级缓存中取得B,完成初始化

为什么要三级缓存?二级不行吗?

不可以,主要是为了生成代理对象。

因为三级缓存中放的是生成具体对象的匿名内部类,他可以生成代理对象,也可以是普通的实例对象。

使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。

假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,BeanPostProcessor去生成代理对象之后,覆盖掉二级缓存中的普通Bean对象,那么多线程环境下可能取到的对象就不一致了。

解释下什么是AOP

面向切面编程。Spring AOP 基于动态代理的方式实现。

在业务代码的前后做一些增强处理。

是将那些与业务⽆关,却为业务模块所共同调⽤的逻辑封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。⽐如:权限认证、⽇志、事务处理。

实例

AOP的代理有哪⼏种⽅式

  • ⽬标对象的实现类实现了接⼝ -> JDK 动态代理
  • 没有实现接口 -> CGLIB

JDK 动态代理和 CGLIB 代理有什么区别?

JDK 动态代理:

  • 针对类实现了某个接口。
  • 基于反射的机制实现,生成一个实现同样接口的一个代理类,然后通过invoke重写方法的方式,实现对代码的增强。

CGLIB 代理:

  • 针对没有实现接口。
  • 底层原理是基于 asm 第三方框架,通过修改字节码生成一个子类,然后重写父类的方法,实现对代码的增强。

Spring 中的事物传播行为

事务的传播性一般用在事务嵌套的场景,比如一个事务方法里面调用了另外一个事务方法,那么两个方法是各自作为独立的方法提交还是内层的事务合并到外层的事务一起提交,这就是需要事务传播机制的配置来确定怎么样执行。

  • 支持当前事务:如果当前存在事务,则加入该事务;如果当前没有事务,则
    • required:创建一个新的事务
    • supports:以非事务的方式继续运行
    • mandatory:抛出异常
  • 不支持当前事务
    • requires_new:创建一个新的事务,如果当前存在事务,则把当前事务挂起
    • not_supported:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    • never:以非事务方式运行,如果当前存在事务,则抛出异常。
  • 其他:
    • nested:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于required

Spring事务失效的原因

  • 事务注解@Transactional放在了非public(private,protected)方法上
  • 数据库本身不支持事务
  • 当前类调用(因为事务本质上是AOP动态代理,自己没法代理自己)
  • bean没有被spring管理
  • 配置的事务传播为不支持事务的那几种support,not_support,never
  • 异常被catch,没法知道有没有错要不要回滚
  • 使用cglib代理的时候,事务注解写到了接口方法上
  • 没有指定rollbackfor异常

注入方式

  • 构造器注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
  • setter注入:Setter 方法注入是容器通过调用无参构造器或无参 static 工厂方法实例化 bean 之后,调用该 bean 的 Setter 方法,即实现了基于 Setter 的依赖注入。

@Component 和 @Bean 的区别

都是用来注册bean的

  • @Component 注解作用于类,@Bean注解作用于方法(表示方法返回的类要注册为bean)
  • 引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现

BeanFactory和FactoryBean的区别

BeanFactory定义了IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口,也就是Spring IOC所遵守的最底层和最基本的编程规范。在Spring代码中,BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,都是附加了某种功能的实现。

FactoryBean是一个工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。产生一个能生产对象的工厂类。getObject方法。

SpringMVC面试题

SpringMVC 的工作原理/执行流程

  • DispatcherServlet 捕获请求
  • HandlerMapping 解析请求对应的 Handler
  • HandlerAdapter 会根据 Handler 来调用真正的处理器来处理请求,并处理相应的业务逻辑
  • 处理器返回一个模型视图 ModelAndView
  • 视图解析器进行解析,返回一个视图对象,
  • DispatcherServlet 渲染数据,返回给用户

常用的注解

  1. @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径;
  2. @RequestBody:注解实现接收 HTTP 请求的 json 数据,将 json 转换为 Java 对象;
  3. @ResponseBody:注解实现将 Controller 方法返回对象转化为 json 对象响应给客户

RequestMapping的属性

value:指定请求的实际地址

method:指定请求的method类型, GET、POST、PUT、DELETE 等

consumes:指定处理请求的提交内容类型

produces:指定返回的内容类型

params:指定 request 中必须包含某些参数值是,才让该方法处理

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

SpringMVC 的控制器是不是单例模式,如果是会有什么问题,怎么解决?

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