spring面试题

1.谈谈你对 Spring 的理解?

spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架
通过控制反转达到松耦合的目的
提供了面向切面编程的支持,允许通过分离应用的业务逻辑与系统服务进行内聚性的开发
包含并管理应用对象(bean)的配置和生命周期,这个意义上是一个容器
将简单的组件配置、组合成为复杂的应用,这个意义上是一个框架
Ioc它是将对象的创建权交由工厂(spring),程序中如果需要对象,从工厂(spring)中获取;解除类与类之间的耦合
AOP底层使用的是动态代理;使用配置的方式来完成动态代理要实现的功能。在不修改源码的基础上,对目标对象中方法进行增强。实现业务之间解耦。

2.切⼊点、通知、连接点、切⾯是什么

切入点:目标对象中要被增强的方法;

通知:要增强的功能;

连接点:目标对象中可以被增强的方法;

切面:切入点和通知的组合

3.springAOP代理方式有几种,怎么配置,实现原理是什么 

springAOP代理方式有几种

JDK动态代理:目标类必须实现一个接口

CGLIB动态代理:目标类不能是最终类

4.spring常用的注解 

1.IOC相关的注解:

1.创建Bean注解:@Component @Service @Repository @Controller

2.依赖注入注解:@Autowired和@Qualifier  @Value

3.作用范围注解:@Scope

4.条件装配:@Conditional

5.配置类和组件扫描:@Configuration   @Bean   @ComponentScan   @Import

6.延迟加载:@Lazy,标注在类上,表示延迟创建bean。第一次使用创建

@Lazy,标注在属性或者方法参数上,先给代理对象

7.配置文件加载:@PropertySource

2.核心

@Order控制Bean的创建顺序

3.事务:

@EnableTransactionManager开启平台事务管理器

@Transactional

4.任务调度,异步

@EnableShaduling   @Schaduled

@EnbaleAync    @Aync

5.切面注解:

@EnableAspectJAutoProxy

6.spring cache相关注解

@EnableCaching

@Cachable

@CacheEvict

@CachePut

5.@Autowied和@Resource区别 

@Autowird和@Qualifier是spring提供的注解,@Resource是jdk在jsr250中定义的注解

@Autowired: 按照类型注入, 如果IOC容器中有多个bean的类型,和注入的属性类型一致,可能会报错;

判断你的bean是否有加属性autowireCandidate为false,优先排除这些bean;

 在排除后的bean中,看那个bean加了@Primary,优先使用该bean;

 将属性的名称作为bean的id进行注入;

@Autowired + @Qualifier可以根据id注入:

@Autowired    @Qualifier("adUserMapper")

@Resource :  该注解等价于@Autowired + @Qualifier

6、Spring由哪些模块组成?

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

Spring常见的模块说明:

1、Spring Core(核心容器): 核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用

BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开

2、Spring Context(应用上下文): 应用上下文: 是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮

件、国际化、校验和调度功能

3、SpringAOP(面向切面编程):是面向对象编程的有效补充和完善,Spring的AOP是基于动态代理实现的

4、SpringDao(JDBC和Dao模块): JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错

误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接

5、Spring ORM(对象实体映射):Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL

Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

6、Spring Web(Web模块):Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集

成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作

7、Spring Web MVC(MVC模块):MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳

了大量视图技术,其中包括JSP、POI等,模型由JavaBean构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码,由c的事情。

Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业

务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

7、在Spring中有几种配置Bean的方式?(高频)

配置方式:

1、基于XML的配置

2、基于注解的配置

3、基于Java的配置

8、BeanFactory和ApplicationContext有什么区别?(高频)

1、BeanFactory:BeanFactory在启动的时候不会去实例化Bean,当从容器中拿Bean的时候才会去实例化;

2、ApplicationContext:ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例

化;

9、Spring框架中的单例bean是线程安全的吗?(高频)

肯定不是线程安全的,当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对该单列状态的修改,则必须考虑线程同步问题。Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态,所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话,就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

10、Spring Bean有哪些作用域,它们之间有什么区别?(高频)

1、singleton :这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维

护 。

2、prototype :原形范围与单例范围相反,为每一个bean请求提供一个实例 。

3、request :在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后, bean会失效并被垃圾回收器回收 。

4、session:与请求范围类似,确保每个session中有一个 bean 的实例,在session过期后, bean会随之失效 。

11、你用过哪些重要的Spring注解?(高频)

1、@Controller - 用于 Spring MVC 项目中的处理器类。

2、@Service - 用于服务类。

3、@RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。

4、@ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。

5、@PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。

6、@Autowired - 用于在 spring bean 中自动装配依赖项。通过类型来实现自动注入bean。和@Qualifier注解配合使用可以实现根据name注入bean。

7、@Qualifier - 和@Autowired一块使用,在同一类型的bean有多个的情况下可以实现根据name注入的需求。

8、@Scope - 用于配置 spring bean 的范围。

9、@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。

10、@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)

12、请解释一下spring框架有哪些自动装配模式,它们之间有何区别?(高频)

spring的自动装配功能的定义:无须在Spring配置文件中描述javaBean之间的依赖关系(如配置<property><constructor-arg>)。

自动装配模式:

1、no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean 定义中用标签明确的设置依赖关系 。

2、byName:该选项可以根据bean名称设置依赖关系 。 当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹

配的bean。 如果找到的话,就装配这个属性,如果没找到的话就报错 。

3、byType:该选项可以根据 bean 类型设置依赖关系 。 当向一个 bean 中自动装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个

匹配的 bean。 如果找到的话,就装配这个属性,如果没找到的话就报错 。

4、constructor :构造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的

bean ,那么将会抛出异常 。

5、default:该模式自动探测使用构造器自动装配或者byType自动装配 。 首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如

果在bean内部没有找到相应的 构造器或者是无参构造器,容器就会自动选择 byTpe 的自动装配方式 。

2 aop原理

13、spring中aop的底层是怎么实现的?(高频)

Spring中AOP底层的实现是基于动态代理进行实现的。

常见的动态代理技术有两种:JDK的动态代理和CGLIB。

两者的区别如下所示:

1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类

2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法进行增强,但是因为采用的是继承,所以该类或方法最好不要声明为

final,对于final类或方法,是无法继承的。

Spring如何选择是用JDK还是cglib?

1、当bean实现接口时,会用JDK代理模式

2、当bean没有实现接口,会用cglib实现

3、可以强制使用cglib

14、spring aop机制都有哪些应用场景?(高频)

应用场景:

1、统一日志处理

2、统一幂等性的处理

3、spring中内置的事务处理

AOP使用步骤

1.导入依赖,Spring-boot-starter-aop依赖包

2.定义切点,并定义切点在哪些方法执行,采用@Pointcut注解完成

3.利用通知的5中类型@Before、@After、@AfterReturning、@AfterThrowing 、@Around来完成在某些切点的增强和动作

 

 

3 事务管理

15、spring事务的实现方式以及原理?(高频)

Spring支持编程式事务管理声明式事务管理两种方式!

编程式事务控制:需要使用TransactionTemplate来进行实现,这种方式实现对业务代码有侵入性,因此在项目中很少被使用到。

声明式事务管理:声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在

目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,

便可以将事务规则应用到业务逻辑中。

16、什么是事务的传播行为?在Spring框架中都有哪些事务的传播行为?

Spring的事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法对事务的态度。举例:methodA事务方法调用methodB事务方

法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。

在Spring中提供了7种事务的传播行为:

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

2、REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

3、SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

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

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

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

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

17、spring如何管理事务的?(高频)

Spring事务管理主要包括3个接口,Spring事务主要由以下三个共同完成的:

1、PlatformTransactionManager:事务管理器,主要用于平台相关事务的管理。

主要包括三个方法:

① commit:事务提交。

② rollback:事务回滚。

③ getTransaction:获取事务状态。

2、TransacitonDefinition:事务定义信息,用来定义事务相关属性,给事务管理器PlatformTransactionManager使用

主要包含的方法:

① getIsolationLevel:获取隔离级别。

② getPropagationBehavior:获取传播行为。

③ getTimeout获取超时时间。

④ isReadOnly:是否只读(保存、更新、删除时属性变为false--可读写,查询时为true--只读)

3、TransationStatus:事务具体运行状态,事务管理过程中,每个时间点事务的状态信息。

主要包含的方法:

① hasSavepoint():返回这个事务内部是否包含一个保存点。

② isCompleted():返回该事务是否已完成,也就是说,是否已经提交或回滚。

③ isNewTransaction():判断当前事务是否是一个新事务。

18、spring事务什么情况下会失效?(高频)

事务失效的常见场景:

1、数据库引擎不支持事务:这里以 MySQL为例,其MyISAM引擎是不支持事务操作的,InnoDB才是支持事务的引擎,一般要支持事务都会使用

InnoDB。

2、bean没有被Spring 管理

3、方法不是public的:@Transactional只能用于public的方法上,否则事务不会失效。

4、自身调用问题

5、数据源没有配置事务管理器

6、异常在方法内部通过try...catch处理掉了

7、异常类型错误:事务默认回滚的是:RuntimeException

因为默认回滚的是:RuntimeException,如果你想触发其他异常的回滚,需要在注解上配置一下,如:

@Transactional(rollbackFor = Exception.class)

4 循环依赖

19、请解释一下spring bean的生命周期?

1、实例化Bean:

反射 BeanDefinition

  • 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用

    createBean进行实例化。

  • 对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。(BeanDefinition是Spring 中极其

    重要的一个概念,它存储了bean对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等。BeanDefinition对象的创建时通过各种

    bean的配置信息进行构建 )

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

的设置属性的接口完成依赖注入。

3、处理Aware接口:接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

  • 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就

    是Spring配置文件中Bean的id值。

  • 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

  • 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文。

4、Bean的后置处理器(BeanPostProcessor):如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用

postProcessBeforeInitialization方法。由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

5、InitializingBean 与 init-method:如果Bean在Spring配置文件中配置了init-method 属性,则会自动调用其配置的初始化方法。

6、Bean的后置处理器(BeanPostProcessor):如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj,

String s)方法;

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

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

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

20、spring中的aop是在bean生命周期的哪一步实现的?

Spring的AOP是通过AspectJAwareAdvisorAutoProxyCreator来实现的

21、什么是Spring的循环依赖?(高频)

简单的来说就是A依赖B的同时,B依赖A。在创建A对象的同时需要使用的B对象,在创建B对象的同时需要使用到A对象。

 

22、出现循环依赖以后会有什么问题?(高频)

对象的创建过程会产生死循环

 

23、spring如何解决循环依赖的?(高频)

Spring解决循环依赖是通过三级缓存

缓存源码名称作用
一级缓存 singletonObjects 单例池; 缓存已经经历了完整声明周期, 已经初始化完成的bean对象
二级缓存 earlySingletonObjects 缓存早期的bean对象(生命周期还没有走完)
三级缓存 singletonFactories 缓存的是ObjectFactory, 表示对象工厂, 用来创建某个对象的

步骤为:

1、实例化A得到A的原始对象

2、将A的原始对象存储到二级缓存(earlySingletonObjects)中

3、需要注入B,B对象在一级缓存中不存在,此时实例化B,得到原始对象B

4、将B的原始对象存储到二级缓存中

5、需要注入A,从二级缓存中获取A的原始对象

6、B对象创建成功

7、将B对象加入到一级缓存中

8、将B注入给A,A创建成功

9、将A对象添加到一级缓存中

三级缓存的作用:

从上面这个分析过程中可以得出,只需要一个缓存就能解决循环依赖了,那么为什么Spring中还需要singletonFactories ?

基于上面的场景想一个问题:如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象,此时就会出现,对于A而言,它的

Bean对象其实应该是AOP之后的代理对象,而B的a属性对应的并不是AOP之后的代理对象,这就产生了冲突。 也就是说, 最终单例池中存放的A对象

(代理对象)和B依赖的A对象不是同一个。

所以在该场景下, 上述提到的二级缓存就解决不了了。那这个时候Spring就利用了第三级缓存singletonFactories来解决这个问题。

 

singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,生成完原始对象之后,就会构造一个ObjectFactory存入

singletonFactories中,后期其他的Bean可以通过调用该ObjectFactory对象的getObject方法获取对应的Bean。

整体的解决循环依赖问题的思路步骤为:

1、实例化A,得到原始对象A,并且同时生成一个原始对象A对应的ObjectFactory对象

2、将ObjectFactory对象存储到三级缓存中

3、需要注入B,发现B对象在一级缓存和二级缓存都不存在,并且三级缓存中也不存在B对象所对应的ObjectFactory对象

4、实例化B,得到原始对象B,并且同时生成一个原始对象B对应的ObjectFactory对象,然后将该ObjectFactory对象也存储到三级缓存中

5、需要注入A,发现A对象在一级缓存和二级缓存都不存在,但是三级缓存中存在A对象所对应的ObjectFactory对象

6、通过A对象所对应的ObjectFactory对象创建A对象的代理对象

7、将A对象的代理对象存储到二级缓存中

8、将A对象的代理对象注入给B,B对象执行后面的生命周期阶段,最终B对象创建成功

9、将B对象存储到一级缓存中

10、将B对象注入给A,A对象执行后面的生命周期阶段,最终A对象创建成功,将二级缓存的A的代理对象存储到一级缓存中

 它有两个注意点:

1、后面的生命周期阶段会按照本身的逻辑进行AOP, 在进行AOP之前会判断是否已经进行了AOP,如果已经进行了AOP就不会进行AOP操作了。

2、singletonFactories : 缓存的是一个ObjectFactory,主要用来去生成原始对象进行了AOP之后得到的代理对象,在每个Bean的生成过程中,都会提前

暴露一个工厂,这个工厂可能用到,也可能用不到,如果没有出现循环依赖依赖本bean,那么这个工厂无用,本bean按照自己的生命周期执行,执行完后

直接把本bean放入singletonObjects中即可,如果出现了循环依赖依赖了本bean,则另外那个bean执行ObjectFactory提交得到一个AOP之后的代理对

象(如果没有AOP,则直接得到一个原始对象)。

24、只有一级缓存和三级缓存是否可行?(高频)

不行,每次从三级缓存中拿到ObjectFactory对象,执行getObject()方法又会产生新的代理对象,因为A是单例的,所有这里我们要借助二级缓存来解决这

个问题,将执行了objectFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍objectFactory.getObject()方法再产

生一个新的代理对象,保证始终只有一个代理对象。

 

总结:所以如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行

objectFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象。

25、构造方法出现了循环依赖怎么解决?(高频)

解决方案:使用@Lazy注解

在构造参数前面加了@Lazy注解之后, 就不会真正的注入真实对象, 该注入对象会被延迟加载 , 此时注入的是一个代理对象 。

 

 

 

 

 

 

 

 

 

 

 

posted @   英俊潇洒的萨克君  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示