spring面试题

序号内容
1基础面试题
2JVM面试题
3多线程面试题
4MySql面试题
5集合容器面试题
6设计模式面试题
7分布式面试题
8Spring面试题
9SpringBoot面试题
10SpringCloud面试题
11Redis面试题
12Mybatis面试题
13网络面试题
14Linux、Kubenetes面试题
15消息队列面试题
16Netty面试题

对spring的理解

它是一个分层的 一站式、轻量级开源框架,为开发 Java 应用程序提供全面的基础架构支持。Spring 负责基础架构,因此 Java 开发者可以专注于应用程序的开发。 Spring最根本的使命是解决企业级应用开发的复杂性,即简化Java开发。

  • 基于 POJO 的轻量级和最小侵入性编程。
  • DI 机制将对象之间的依赖关系交由框架处理,减低组件间的耦合性。
  • 基于 AOP 技术支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。
  • 对于主流的应用框架提供了集成支持。

Spring的依赖注入

控制反转IOC的主要实现方式:依赖注入和依赖查找。

依赖注入:组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。

依赖注入的原则

应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由IoC容器负责。 容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造器传递给需要的对象。

依赖注入的实现方式

构造器注入

构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。

setter方法注入

Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。

spring用到了哪些设计模式

1、单例模式

Spring中的Bean默认为singleton单例

2、原型模式

3、模板模式

主要用来解决代码重复的问题。Spring提供了非常多的模板类来减少重复代码,基本都是以Template结尾,比如RestTemplate,JmsTemplate,JdbcTemplate。

4、观察者模式

主要用于当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知,在Spring中一般以Listener结尾,比如ApplicationListener等等。

5、工厂模式

Spring的BeanFactory类,就是使用了简单工厂模式。它主要提供getBean()方法,用来创建对象的实例;我们见得比较多的ApplicationContext也是继承自BeanFactory。

6、适配器模式

在Spring,只要是以Adapter命名的类基本都是适配器模式的应用。比如MVC模块中的HandlerAdapter。

7、装饰者模式

在Spring中,只要见到以Wrapper命名的类基本都是使用装饰器模式。比如BeanWrapper,用来访问Bean的属性和方法。

8、代理模式

比如AOP模块中的AopProxy,用到了JDK的动态代理和CGLIB字节码生成技术;

9、策略模式

Spring中Bean的实例化采用的就是策略模式。因为Bean的实例化包含原生对象的实例化,和代理对象的实例化,不同对象实例化的逻辑也不一样,所以实例化策略也不一样,比如SimpleInstantiationStrategy就是Spring中默认的实例化策略。

10、责任链模式

11、委托者模式

@Autowired 和 @Resource 的区别

相同点

都是用来装配Bean的。都写写在字段和setter方法上,如果都写在字段上,那么就不需要再写setter方法。

不同点

1、@Autowired是按照类型(byType)装配依赖的对象的,默认情况下要求依赖的对象必须存在。可以使用required = false 来允许依赖的对象为空。如果想按照名称来装配,可以结合@Qualifier注解使用。当系统中存在多个相同类型的Bean时,如果不使用@Qualifier程序启动是会报错。

2、 @Resource默认是按照名称注入的。@Resource有两个重要的属性,name 和 type,spring将 @Resource注解的name属性解析为bean的名字,type属性解析为bean的类型。如果使用name,则是根据名称(byName)自动注入,如果使用type,则是根据类型(byType)自动注入。如果都不使用,则是通过使用反射机制,使用根据名称注入(byName)。

3、@Autowired 是spring提供的注解,@Resource 是JDK提供的注解

BeanFactory 和 ApplicationContext 的区别?

二者都是 Spring 框架的两大核心接口,都可以当做 Spring 的容器。其中 ApplicationContext 是 BeanFactory 的子接口。

BeanFactory 是 Spring 里面最底层的接口,包含了各种 Bean 的定义,读取配置文档,管理 Bean 的加载、实例化,控制 Bean 的生命周期,维护对象之间的依赖关系等功能。

ApplicationContext 接口作为 BeanFactory 的派生,除了提供 BeanFactory 所具有的功能外,还提供了更完整的框架功能:

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

Spring 中常用的注解

@Controller

@Service

@RequestBody

@ComponentScan

@Index

spring 5.0提供。在应用中有大量使用@ComponentScan扫描的package包含的类越多的时候,Spring模式注解解析耗时就越长。@Index注解它可以为Spring的模式注解添加索引,以提升应用启动性能。

就是在编译的时候,被@Index注解所标识的java类先读到一个文计中,这个文件就相当于索引表,系统启动的时候就不需要扫描所有需要加载的Bean了,读这个文件就可以扫描到所有的需要加载到容器中的对象的类型。

pom.xml中需要添加spring-context-indexerjar包。重新clean install下项目,会在target的classes文件夹下的META-INF下生成一个spring.components文件。

@Import

@Import注解用来导入配置类或者一些需要前置加载的类到IOC容器中。,import 注解是标签的替换,可以导入配置类,也可以导入普通类。也可以导入ImportSelector接口所实现的相关配置类,调用配置类中的selectImports方法。

循环依赖

循环依赖指的是两个类中的属性各自依赖对方,比如A类中有B属性,B类中有A属性,

这样子就造成了spring在实例化其中一个类A的时候,填充属性的时候要去实例化另外一个类B,而填充另外一个类B属性A的时候又发现需要原来的那个类A,导致循环引用, 无限创建

循环依赖分为自身依赖自身,互相循环依赖,多组循环依赖。

解决循环依赖,就是在实例化一个对象的时候能够找到另一个已经创建好的对象,打破相互找不到。提前将创建好的对象暴露出来,创建好的对象能被发现。

spring解决循环依赖

一级缓存

存放的是正式的被创建出来的对象。存放所有spring创建出来的bean对象。不是为了解决循环依赖用的。

二级缓存

存放半成品的实例对象。

三级缓存

存放objectFactory对象。没有AOP不需要三级缓存。

为什么需要三级缓存

三级缓存主要处理的是AOP的代理对象,存储的是一个ObjectFactory。三级缓存考虑的是代理对象,而二级缓存考虑的是性能,从三级缓存的工厂中创建出来的对象,再放到二级缓存。这样就不用每次都从工厂拿对象了。

没有三级缓存可以解决循环依赖吗

没有三级缓存是可以解决循环依赖的,解决循环依赖主要是二级缓存。

Aware接口的作用

Aware是一个标记性的超接口(顶级接口),指示了一个Bean有资格通过回调方法的形式获取Spring容器底层组件。就是只要实现了Aware子接口的Bean都能获取到一个Spring底层组件。例如:BeanFactoryAware、BeanNameAware、ApplicationContextAware。

BeanFactoryAware:实现该接口的Bean,可以获取到BeanFactory组件对象。

BeanNameAware:实现该接口的Bean,可以获取到Bean的名称。

ApplicationContextAware:实现该接口的Bean,可以获取到应用上下文。

spring 自动装配 bean 有哪些方式

Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。

  • byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
  • byType:通过参数的数据类型进行自动装配
  • constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
  • autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。

@Autowired注解自动装配的过程

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

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

Spring框架中的单例bean是线程安全的吗

线程不安全。spring 中的 bean 默认是单例模式,spring框架中并没有对单例bean进行多线程的封装处理。

大部分bean是无状态的(例如dao类),如果bean是有状态的话(例如view model 对象),我们可以通过改变bean的作用域,把singleton 改成 prototype,这样请求bean就相当于new bean()了,就保证了线程安全。

spring bean的生命周期

1、如果创建了一个类继承了InstantiationAwareBeanPostProcessorAdapter接口,并在配置文件中配置了该类的注入,即InstantiationAwareBeanPostProcessorAdapter和bean关联,则Spring将调用该接口的postProcessBeforeInstantiation()方法。

2、根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean。

3、如果InstantiationAwareBeanPostProcessorAdapter和bean关联,则Spring将调用该接口的postProcessAfterInstantiation()方法。

4、利用依赖注入完成 Bean 中所有属性值的配置注入。

5、如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。

6、如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。

7、如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。

8、如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。

9、如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。

10、如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。

11、如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。
注意:以上工作完后才能以后就可以应用这个bean了,那这个bean是一个singleton的,所以一般这种情况下我们调用同一个id的bean会是在内容地址相同的实例,当然在spring配置文件中也可以配置非Singleton。

12、如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法将 Spring 中的 Bean 销毁;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

spring bean支持的几种作用域

1、singleton:默认,每个容器中只有一个bean实例,单例的模式由BeanFactory自身来维护。

2、prototype:为每一个bean请求提供一个实例。

3、request:为每一个网络请求创建一个实例,在请求完成后,bean会失效并被垃圾回收器回收。

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

5、global-session:全局作用域。

事务的隔离级别

spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:

ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;

ISOLATION_READ_UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);

ISOLATION_READ_COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;

ISOLATION_REPEATABLE_READ:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;

ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。

事务的传播行为

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

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

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

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

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

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

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

spring事务的实现方式或者管理类型

编程式事务管理

通过编程的方式管理事务,这钟方式带来了很大的灵活性,但是很难维护。

声明式事务管理

事务管理和业务代码分离,只需要通过注解或者XML配置管理事务。

事务注解的本质是什么

@Transactiona注解仅仅是一些和事务相关的元数据,在运行时被事务基础设施读取消费,并使用这些元数据来配置bean的事务行为。大致来说具有两方面功能,一是表明改方法要参与事务,二是配置相关属性来定制事务的参与方式和运行行为。

声明式事务主要得益于spring 的AOP。使用一个事务拦截器在方法调用的前后/周围进行事务增强(advice),来驱动事务完成。

@Transactiona注解即可以标注在类上,也可以标注在方法上。标注在类上默认应用到类中所有的方法。如果方法上也标注了,方法上的优先级要高于类上的。方法要是public的方法,否则@Transactiona注解会不生效

@Transactional但是事务不生效

1、@Transactional注解未标注在public方法上。

AbstractFallbackTransactionAttributeSource#computeTransactionAttribute方法里有段逻辑,如下,指出"事务不作用于非public方法";

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don't allow no-public methods as required.
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }
    ...
 }

2、目标方法使用final修饰。

@Transactional事务是基于AOP的代理,在代理类中实现事务。如果方法使用了final修饰,那么在它的代理类中就无法重写改方法。同样,static修饰的方法也无法通过动态代理变成事务方法。

3、事务方法所在的类未被spring管理。

使用Spring事务的前提是:对象要被Spring IOC容器管理,需要创建bean实例。

4、数据库存储引擎不支持事务。

MySql的MyISAM不支持事务,加了注解也不会生效。

5、未开启事务。

spring boot通过DataSourceTransactionManagerAutoConfiguration类 默认开启了事务。如果是传统的老项目,需要手动在applicationContext.xml配置文件中配置相关参数,开始事务。

6、同一个类中的方法直接内部调用。

方法被事务管理是因为AOP生成了代理对象,但是直接用this调用同类的方法,调用的是目标类对象的方法,不是代理对象的方法,因此事务不会生效。

什么是 AOP 以及作用?

OP 全称(Aspect Oriented Programming),是面向切片编程的简称。

传统的 OOP 开发中代码逻辑是至上而下的过程中会长生一些横切性问题(大量与业务无关的重复代码),这些横切问题会散落在代码的各个地方且难以维护。AOP 的编程思想就是把业务逻辑和横切的问题进行分离,从而达到解耦的目的,使代码的重用性和开发效率高(目的是重用代码,把公共的代码抽取出来)。

即AOP 的作用是对业务逻辑的各个部分进行隔离,降低业务逻辑的耦合性,提高程序的可重用型和开发效率。

作用:可以用在日志、权限、事务、缓存上。

AOP 实现原理

AOP是基于代理实现的。Spring提供了两种代理方式:

  • JDK 动态代理:利用拦截器加反射机制生成一个实现代理接口的匿名类
  • CGlib:利用 ASM 开源包修改字节码生成子类,且不支持 Final 修饰的方法

默认策略是:如果目标类是接口,则使用JDK动态代理,否则使用GClib生成代理。

JDK动态代理和CGLIB动态代理的区别

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

如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

切面 Aspect

aspect 由 pointcount 和 advice 组成,切面是通知和切点的结合。 它既包含了横切逻辑的定义, 也包括了连接点的定义. .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值