Spring面试题总结

一、Spring相关面试题

1、Spring是什么

Spring是一种轻量级的IOC和AOP框架,是为Java应用程序提供基础性服务的一套框架,目的是为了大大简化企业级应用开发,它使得开发者只需要关心业务需求。常见的配置有三种:基于xml;基于注解;基于Java。

主要由以下几个模块组成:
①、Spring Core:核心类库,提供IOC服务;
②、Spring Context:提供框架式的Bean访问方式,以及企业及功能(JNDI,定时任务等);
③、Spring AOP:提供AOP服务;
④、Spring Dao:对JDBC的抽象,简化了数据访问异常处理;
⑤、Spring ORM:对现有ORM框架的集成与支持;
⑥、Spring Web:提供了基本的面向Web的特性,例如多方文件上传;
⑦、Spring MVC:提供了面向Web的MVC实现。

2、Spring的有点有哪些

①、低入侵式,代码污染率极低;
侵入式就是在使用框架的时候继承或者实现框架的类或接口,侵入式对框架的依赖很高,不利于代码的复用。
非侵入式就是不继承或实现类或接口就能实现自己想要的结果,如之前学的Hibernate框架。
②、IOC机制将对相间的关系交由框架处理,减低组件的耦合性;
③、Spring AOP提供横向切面操作,可以将日志、事务、权限、安全等集中式管理,极大的提高了代码的复用;
④、Spring对目前主流框架提供了很好的支持,如MyBatis、Redis等。

3、对Spring AOP的理解

Java的OOP面向对象的思想通过继承允许开发者定义 纵向的关系,但却不适合定义横向的关系,这会导致代码大量重复,效率很低。

AOP,面向切面,是对面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的行为和逻辑进行封装,以便可以重复使用。

AOP实现的关键在于代理模式,AOP的代理有动态代理和静态代理之分:

①、静态代理

AspectJ是静态代理的增强,所谓静态代理就是AOP在编译时就生成代理类,所以也称为编译时增强,它会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强后的AOP对象。

②、动态代理

AOP的动态代理不会去改动字节码,而是在每次运行时都在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回掉原对象的方法。

AOP的动态代理包括JDK代理和CGLIB代理:
JDK代理: 只提供接口的代理,不提支持的代理。核心InvocationHandler接口和Proxy类,InvocationHandler接口通过invoke()方法反射来调用目标类中的代码,动态的将横向逻辑与业务编织在一起;然后Proxy利用InvocationHandler接口动态创建一个符合某一接口的实例,生成目标类的代理对象。

CGLIB代理: 如果代理类没有实现接口,Spring AOP会选择CGLIB来代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成一个类的子类对象,并覆盖其中特定代码并添加增强代码,从而实现AOP。CGLIB是通过继承的方式实现的动态代理,如果一个类由final修饰,则不会是使用CGLIB代理。

关于代理可以阅读:Java三种代理模式

4、理解Spring的IOC

IOC,Inverse Of Controll,控制反转,是创建对象的控制权的转移,之前使用对象的时候都是自己去创建,但在Spring中创建对象这个事情是由Spring容器完成的,并且由Spring容器根据配置文件创建对象和管理各个实例之间的依赖关系,对象与对象之间的松散耦合,也利于功能的复用。

DI,Dependency Injection,依赖注入,和IOC是同一个概念的不同角度的表述,即应用程序在运行时依赖IOC容器来动态注入对象需要的外部资源。

对IOC一种更直观的表达:IOC让对象的创建不用new了,而是通过Spring自动产生,使用Java的反射,根据配置文件在运行时动态的创建对象和管理对象。

Spring的IOC注入方式有三种:setter注入;构造器注入;注解注入
关于Spring的IOC注入方式阅读:Spring全家桶之Spring基础知识

关于IOC与AOP:IOC让相互协作的各个组件保持松散耦合;AOP提高了代码的复用率。

5、BeanFactory与ApplicationContext的区别

BeanFactory和ApplicationContext是Spring的两大和新街口,都可以作为Spring容器,ApplicationContext是BeanFactory的子接口。
在这里插入图片描述
①、BeanFactorySpring最底层的接口,包含Spring Bean的定义,读取Bean的配置文档,管理Bean的加载、实例化,控制Bean的生命周期,维护Bean之间的依赖关系。ApplicationContext作为BeanFactory的子接口,除了拥有BeanFactory的所有功能,还提供了更完整的框架功能:

  • 继承MessageSource,因此支持国际化;
  • 统一的资源文件访问方式
  • 提供在监听器中注册bean的事件
  • 同时加载多个配置文件
  • 载入多个(有继承关系)的上下文,使得每一个上下文都专注于一个指定的层次

②、BeanFactory:使用的是延迟加载的方式注册Bean,即只有当使用到(调用getBean()方法)Bean时才会被加载实例化。这种方式不利于发现Spring的一些配置问题,如果某个Bean的某个属性没有被注入,BeanFactory加载后,只有第一次使用调用getBean()方法的时候才会发生异常。

ApplicationContext:在容器启动的时候一次性创建了所有的Bean,这样就可以在Spring容器启动时发现Spring中存在的配置错误,有利于检查依赖的属性是否注入。ApplicationContext在Spring容器启动时预载入所有的单实例Bean,当需要的时候不用等待创建,因为在Spring容器启动的时候已经创建完成了。

比较:

  • ApplicationContext相当于BeanFactory的不足之处在于占用内存,当Bean较多时,程序启动较慢。
  • BeanFactory通常以编程的方式被创建,而ApplicationContext还能以声明的方式创建,如使用ContextLoader。
  • 二者都支持使用BeanPostProcessor和BeanFactoryPostProcessor,但二者的区别是:BeanFactory需要手动注册,而ApplicationContext是自动注册。
6、Spring Bean的生命周期
①、实例化Bean

对于BeanFactory容器,当客户向容器请求一个尚未初始化的Bean的时候,或者是初始化的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的Bean。

②、设置对象属性(依赖注入)

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition的信息以及通过BeanWrapper提供的设置属性的接口完成依赖注入。

③、处理Aware接口

接着Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例诸如给Bean:

  • 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,这里的beanId就是Spring配置文件中的Bean 的 id值。
  • 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂本身。
  • 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文。
④、BeanPostProcessor

如果相对Bean进行一些自定义的处理,可以实现BeanPostProcessor接口,并调用postProcessBeforeInitialization(Object obj, String s)方法。

⑤、InitializingBean 与 init-method

如果在Spring配置文件中配置了init-method方法,会自动调用配置的初始化方法。

⑥、postProcessAfterInitialization(Object obj, String s)

如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

⑦、DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法。

⑧、destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

7、Spring支持的几种bean的作用域

Spring容器中bean可划分为5个范围:

  • ①、singleton,默认,每个容器只有一个bean的实例,单例的模式由BeanFactory自身维护。
  • ②、prototype,为每一个bean请求提供一个实例。
  • ③、request,为每一个网络请求创建一个实例,在请求完成以后,bean会失效并会被垃圾回收机制回收。
  • ④、session,与request类似,确保每个session范围内有一个bean实例,session过期后,bean随之失效。
  • ⑤、global-session,全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

例子:

<bean id="testManager" class="com.sw.TestManagerImpl" scope="singleton" />  
8、Spring框架中单例的Beans是线程安全的吗?

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

9、Spring如何处理线程并发问题

一般情况下,只有无状态的Bean才可以在多线程状态下进行共享,在Spring中大多数Bean的作用域都可以声明为singleton,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了时间换空间的方式,仅提供一个变量,不同的线程在访问前要获取锁,没获得锁的线程则要排队,ThreadLocal采用空间换时间的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离多个线程访问对数据的访问冲突,因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

有关有状态和无状态Bean可以阅读:
Spring的并发问题——有状态Bean和无状态Bean

10、Spring的自动装配

在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用@Autowired来配置自动装载模式。

在Spring框架xml配置中共有5种自动装配:

(1)no: 默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。

(2)byName: 通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。

(3)byType: 通过参数的数据类型进行自动装配。

(4)constructor: 利用构造函数进行装配,并且构造函数的参数通过byType进行装配。

(5)autodetect: 自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

基于注解的方式:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动Spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

如果查询的结果不止一个,那么@Autowired会根据名称来查找;

如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

@Autowired可用于:构造函数、成员变量、Setter方法
注:@Autowired和@Resource之间的区别
(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

11、Spring用到了哪些设计模式

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

(2)单例模式:Bean默认为单例模式。

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

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

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

12、Spring事务实现和实现原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

(1)Spring事务的种类:

spring支持编程式事务管理和声明式事务管理两种方式:

①编程式事务管理使用TransactionTemplate。

②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。
声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

(2)Spring的事务传播行为:

Spring事务的传播行为说的是,当多个事务同时存在的时候,Spring如何处理这些事务的行为。

① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

② PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

③ PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

④ PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

⑦ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

(3)Spring中的隔离级别:
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

② ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

④ ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

13、Spring框架中有哪些不同类型的事件?

Spring 提供了以下5种标准的事件:

(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。

(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。

14、Spring AOP相关

阅读:Spring全家桶之SpringAOP

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值