Spring面试基础

1. 你认为Spring的核心是什么

  1. spring是一个开源框架,是一个生态和基石
  2. spring为了简化企业开发而生的,使得开发更加优雅和简洁
  3. spring是一个IOC和AOP容器框架,IOC是控制反转,就是本来自己创建,但是现在我交给spring容器让他帮我创建;AOP是面向切面编程;容器包含并管理应用对象的生命周期,好比桶装水,spring是桶而对象就是水

2. 如何理解约定优于配置

  • 约定优于配置也称为按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,获得简单的好处,而又不失灵活性,具体如下
  1. 开发人员只需要规定应用中不符合约定的部分
  2. 在没有规定配置的地方,采用默认配置,以力求最简配置为核心思想
  3. 例如maven的目录结构即resource文件夹,src-main-java等;默认配置文件必须是application命名的yml文件或者properties文件;yml文件中的属性等

3. spring boot starter有什么用

  • s p r i n g b o o t springboot springboot通过提供众多起步依赖 ( s t a r t e r ) (starter) (starter)降低项目依赖的复杂度,starter本质是一个Maven项目对象模型 ( P r o j e c t O b j e c t M o d e l , P O M ) (Project Object Model, POM) (ProjectObjectModel,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能,很多 s t a r t e r starter starter的命名都暗示了它们提供的功能
  • 简单来说就是引入一些依赖和初始化配置,通过 s t a r t e r starter starter导入包

4. Spring用到了哪些设计模式

  1. 简单工厂,BeanFactory就是典型的工厂模式,通过传入一个唯一标识来获得Bean对象
  2. 工厂方法,实现了FactoryBean接口的Bean是一类叫做factory的bean,其特点是spring在使getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean的getObject()方法的返回值
  3. 单例模式,Spring依赖注入bean实例默认时单例的,Spring的依赖注入都是发生在AbstractBeanFactory的getBean里,getBean的doGetBean方法调用getSingleton完成bean的创建
  4. 代理模式,AOP底层就是动态代理模式的实现,即切面在应用运行的时刻被织入,一般情况下,在织入切面时,AOP容器会为目标对象创建动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的
  5. 观察者模式,Spring的事件驱动模型使用的是观察者模式,Spring中观察者模式常用的地方是listener的实现
    等等

5. Springboot的启动流程

  • 首先创建项目之后会生成一个默认的*Application入口类,我们是通过该类的run方法启动Spring Boot项目的,通过run方法进行SpringApplication类的实例化操作,然后再针对实例化对象调用另外一个run方法完成整个项目的初始化和启动,如下图
    在这里插入图片描述

源码分析

public ConfigurableApplicationContext run(String... args) {
	long startTime = System.nanoTime();// 返回最精确的当前时间, 以毫微秒为单位
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();// 初始化启动上下文
	ConfigurableApplicationContext context = null;
	configureHeadlessProperty();// 设置不用显示器也能启动
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting(bootstrapContext, this.mainApplicationClass);// 启动监听
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 创建ApplicationArguments对象
		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		configureIgnoreBeanInfo(environment);// 加载属性配置
		Banner printedBanner = printBanner(environment);// 打印banner图标
		context = createApplicationContext();// 创建容器
		context.setApplicationStartup(this.applicationStartup);
		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 准备容器
		refreshContext(context);// 初始化容器
		afterRefresh(context, applicationArguments);// 初始化之后执行
		Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);// 时长统计
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);// 打印启动日志
		}
		listeners.started(context, timeTakenToStartup);// 通知监听器, 容器完成启动
		callRunners(context, applicationArguments);// 调用ApplicationRunner和CommandLineRunner的运行方法
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, listeners);// 异常处理
		throw new IllegalStateException(ex);
	}
	try {
		Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
		listeners.ready(context, timeTakenToReady);// 通知监听器容器正在运行
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

6. Spring Boot自动装配的过程

  • 使用Spring Boot的时候,我们只需要引入相应的 s t a r t e r s starters starters,Spring Boot启动时便会自动加载相关依赖,配置相关的初始化参数,以最快捷、简单的方式对第三方软件进行集成,这便是Spring Boot的自动配置功能,核心部分如下图
    在这里插入图片描述
  • 整个自动装配的过程是首先springboot通过@EnableAutoConfiguration注解开启自动配置,加载spring.factories中加载的各种AutoConfiguration类,当某个AutoConfiguration类满足其注解@Conditional指定的生效条件时,实例化该AutoConfiguration类中定义的Bean,并注入Spring容器,就可以完成依赖框架的自动化配置

7. Spring Boot注解

7.1. @SpringBootApplication注解

  • 在Spring Boot入口类中,唯一的一个注解就是@SpringBootApplication,它是Spring Boot项目的核心注解,这里面主要有三个注解,@SpringBootConfiguration作用是标注这个类是一个配置类,它是@Configuration的派生注解,@EnableAutoConfiguration作用是启动Spring应用程序上下文时进行自动配置,它会尝试猜测项目可能需要的Bean,自动配置通常是基于项目classpath中引入的类和已定义的Bean来实现的。在此过程中,被自动配置的组件来自项目自身和项目依赖的jar包中,@ComponentScan定义用于扫描的路径中找出标识了需要装配的类自动装配到spring的bean容器中

7.2 @Import注解

  • @EnableAutoConfiguration的关键功能是通过@Import注解导入的ImportSelector来完成的,从源码得知@Import(AutoConfigurationImportSelector.class)是@EnableAutoConfiguration注解的组成部分,也是自动配置功能的核心实现者

7.3 @Conditional注解

  • @Conditional注解是Spring4.0版本引入的新特性,可根据是否满足指定的条件来决定是否进行Bean的实例化及装配,如设定当类路径下包含某个jar包的时候才会对注解的类进行实例化操作。总之就是根据一些特定条件来控制Bean实例化的行为

8. Spring的核心是什么

  • Spring框架包含众多模块,如Core、Testing、Data Access、Web Servlet等,其中Core是整个Spring框架的核心模块,Core模块包含了IoC容器、AOP功能、数据绑定、类型转换等一系列的基础功能,而这些功能以及其他模块的功能都是建立在IoC和AOP之上的,所以IoC和AOP是Spring框架的核心
  • IoC(Inversion of control)是控制反转的意思,这是一种面向对象编程的设计思想,在不采用这种思想的情况下,我们需要自己维护对象与对象之间的依赖关系,很容易造成对象之间耦合度过高,在一个大型的项目中十分的不利于代码的维护。IoC可以解决这种问题,它可以帮我们维护对象之间的依赖关系,降低对象之间的耦合度
  • 那么IoC的实现方式是什么呢?答案是DI(Dependency Injection),也就是依赖注入,实现依赖注入的关键是IoC容器,它的本质是一个工厂
  • AOP是面向切面编程思想,这种思想是对OOP的补充,它可以在OOP的基础上进一步提升编程的效率。简单说,他可以解决一些组件的共性需求如权限检查,记录日志,事务管理等,在AOP思想下,我们可以把解决共性需求的代码独立出来,然后通过配置的方式,声明这些代码在什么地方,什么时机调用,当满足调用条件时,AOP会将该业务代码织入到我们指定的位置,从而统一解决了问题,又不需要修改这一批组件的代码

9. 说一说Spring容器

  • Spring主要提供了两种类型的容器, B e a n F a c t o r y BeanFactory BeanFactory A p p l i c a t i o n C o n t e x t ApplicationContext ApplicationContext
  • B e a n F a c t o r y BeanFactory BeanFactory是基础类型的IoC容器,提供完成的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,而且功能要求不是很严格的场景, B e a n F a c t o r y BeanFactory BeanFactory是比较合适的IoC容器选择
  • A p p l i c a t i o n C o n t e x t ApplicationContext ApplicationContext是在BeanFactory的基础上构建的,是相对比较高级的容器实现,除了拥有 B e a n F a c t o r y BeanFactory BeanFactory的所有支持, A p p l i c a t i o n C o n t e x t ApplicationContext ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等。 A p p l i c a t i o n C o n t e x t ApplicationContext ApplicationContext所管理的对象,在该容器启动之后,默认全部初始化并绑定完成。所以相对于 B e a n F a c t o r y BeanFactory BeanFactory来说, A p p l i c a t i o n C o n t e x t ApplicationContext ApplicationContext要求更多的系统资源,同时,因为在启动时就完成了所有初始化。容器启动时间较 B e a n F a c t o r y BeanFactory BeanFactory也会长一些。在那些系统资源充足,而且要求更多功能的场景中, A p p l i c a t i o n C o n t e x t ApplicationContext ApplicationContext类型的容器也是比较合适的选择

10. 说一说你对Spring IoC的理解

  • IoC(Inversion of Control)是控制反转的意思,这是一种面向对象的编程思想,在不采用这种思想的情况下,我们需要自己维护对象与对象之间的依赖关系,很容易造成对象之间的耦合度过高,在一个大型项目中这十分的不利于代码的维护。IoC则可以解决问题,它可以帮我们维护对象与对象之间的依赖关系,降低对象之间的耦合度
  • IoC实现的方式是 D I ( D e p e n d e n c y   I n j e c t i o n ) DI(Dependency\ Injection) DI(Dependency Injection),也就是依赖注入,实现依赖注入的关键是IoC容器,它的本质就是一个工厂
  • 在具体的实现中,主要有三种注入方式
  1. 构造方法注入,就是被注入对象可以在它的构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。然后,IoC Service Provider会检查被注入的对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象。构造方法注入方式比较直观,对象被构造完成后,即进入就绪状态,可以马上使用
  2. setter方法注入,通过setter方法,可以更改相应的对象属性。所以,当前对象只要为其依赖对象所相应的属性添加setter方法,
  3. 接口注入,被注入对象如果想要IoC Service Provider为其注入依赖对象,就必须实现某个接口。这个接口提供一个方法,用来为其注入依赖对象。IoC Service Provider最终通过这些接口来了解,应该为被注入对象注入什么依赖对象。相对于前两种依赖注入方式,接口注入比较死板和繁琐

总体来说,构造方法注入和setter方法注入因为其侵入性较弱,且易于理解和使用,所以是现在是使用最多的注入方法。而接口注入因为侵入性较强,近年来已经不流行了

11. 说一说你对Spring AOP的理解

  • AOP(Aspect Oriented Programming)是面向切面编程,它是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面,所谓切面,相当于应用对象间的横切点
  1. 切点(Pointcut):是一个基于正则表达式的表达式,通常一个pointcut会选取程序中的某些我们感兴趣的执行点,或者是程序执行点的集合
  2. 连接点(JointPoint):对应的是具体被拦截的对象,因为Spring只支持方法,所以被拦截的对象往往就是特定的方法,AOP通过动态代理技术把它织入到相应的流程中
  3. 通知(Advice):在选取出来的JointPoint上要执行的操作、逻辑,分为前置、后置、环绕、事后返回和异常通知,它会根据约定织入流程中
  4. 切面(Aspect):是一个可以定义切点、各类通知和引入的内容,SpringAOP将通过它的信息来增强Bean的功能或者将对应的方法织入流程
  5. 织入(Weaving):把切面应用到目标对象来创建新的advised对象的过程
  6. 目标对象(Target):即被代理对象

两种实现方式分别是JDK动态代理和CGLib动态代理

  • JDK动态代理:是Java提供的动态代理技术,可以在运行的时候创建接口的运行实例。SpringAOP默认采用这种方式,在接口的代理实例中织入代码
  • CGLib动态代理:采用底层的字节码技术,在运行时创建子类代理的实例。当目标对象不存在接口时,SpringAOP就会采用这种方式,在子类实例中织入代码

12. AOP的使用场景

  • SpringAOP为IoC的使用提供了更多的便利。一方面,应用可以直接使用AOP的功能,设计应用的横切关注点,把跨越应用程序多个模块的功能抽象出来,并通过简单的AOP应用,灵活的编制到模块中,比如可以通过AOP实现应用程序中的日志功能。另一方面,在Spring内部,一些支持模块也是通过AOP来实现的,比如事务处理,从这两个角度已经可以看到SpringAOP的核心地位了

13. Spring AOP不能对哪些类进行增强

  1. Spring AOP只能对IoC容器中的Bean进行增强,对于不受容器管理的对象不能增强
  2. 由于CGLib采用动态创建的方式生成代理对象,所以不能对final修饰的类进行代理

14. 为什么不全用CGLib还要有jdk动态代理

  • 性能方面,CGLib创建的代理对象比JDK动态代理创建的代理对象高得多。但是CGLib在创建代理对象所花费的时间比JDK多很多。所以,对于单例的对象无需频繁创建代理对象,采用CGLib动态代理比较合适。反之,对于多例的对象因为需要频繁的创建对象,则JDK动态代理更合适

15. Spring如何管理事务

  • Spring支持两种事务模型分别是编程式事务和声明式事务,编程式事务主要是使用TransactionTemplate模板,我们可以将事务管理的范围控制的更为精确,声明式事务主要通过@Transactional注解说明事务特征来实现

16. @Transactional注解的用法

  • @Transactional注解可以作用于接口、接口方法、类以及类方法上。当作用在类上时,该类的所有public方法都将具有该类型的事务属性,同时,我们也可以在方法级别上使用该标注来覆盖类级别的定义
  • Spring建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外@Transactional注解应该只被应用到public方法上,这是由Spring AOP的本质决定的。如果你在protected、private或者默认可见性的方法上使用@Transactional注解,这将被忽略,也不会抛出任何异常
  • 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰

17. @Transactional注解失效场景

  1. 注解在非public方法上,因为在AOP代理的时候事务拦截器在目标方法执行前后进行拦截,CGLib的intercept方法或JDK的invoke方法(它们间接调用的一个方法)会去检查这修饰符是不是public,不是就不会获取@Transactional的属性配置信息,事务无效但不报错
  2. @Transactional注解属性propagation设置错误,设置成了非事务方式
  3. @Transactional注解属性rollbackFor设置错误,需要设置自定义异常回滚,否则按默认未检查uncheck异常,或者Error才回滚事务,其他异常不会触发回滚事务
  4. 在同一个类中方法调用,A和B在同一个类里面,A没有声明事务,而B声明了,如果A中调用了B,在外部调用方法A后,B的事务是不会起作用的。为什么?因为使用Spring AOP代理造成的,只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理
  5. 异常被catch,如果A的try方法中调用了B,但B中抛出了异常,被A的catch语句捕获,那么注解失效
  6. 数据库引擎不支持事务,使用了myIsam之类的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clarence Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值