Spring常见面试题

13 篇文章 1 订阅 ¥9.90 ¥99.00

参考:javaguide程序员大彬

1.什么是Spring?

Spring是个轻量级的框架,通过IOC达到松耦合的目的,通过AOP可以分离应用业务逻辑和系统服务分开,不过配置各种组件时比较繁琐,所以后面才出选了SpringBoot的框架。

2.Spring用了哪些设计模式

BeanFactory用了工厂模式,AOP用了动态代理模式,Bean 用了单例模式,RestTemplate用了模板方法模式,监听器用了观察者模式,SpringMVC中HandlerAdapter用了适配器模式

3.IOC是什么?

IOC:IOC控制反转,是一种思想,把对象的创建和调用从程序员手中交由IOC容器管理,降低对象之间的依赖关系。Spring通过DI(依赖注入)实现了IOC。

依赖注入:DI依赖注入,是IOC的实现,在Spring创建对象的过程中,把对象依赖的属性注入到对象中。
依赖注入有三种方式:构造器注入、set注入、接口注入

4.将类声明为Bean的注解有哪些?

  • @Component:通用的注解,可标注任意类为 Spring 组件。

  • @Repository : 对应持久层。

  • @Service : 对应服务层。

  • @Controller : 对应SpringMVC控制层。

5.注入Bean有哪些方式?

  1. @Configuration + @Bean

    @Configuration用来声明一个配置类,然后使用 @Bean 注解,用于声明一个Bean,将其加入到Spring容器中。

  2. 通过包扫描特定注解的方式

    @ComponentScan放置在我们的配置类上,然后可以指定一个路径,进行扫描带有特定注解的Bean,然后加至容器中。

    特定注解包括@Controller、@Service、@Repository、@Component

  3. @Import注解导入:

    @Import注解平时开发用的不多,经常搭配自定义注解进行使用,然后往容器中导入一个配置文件。

6.Spring自动装配有哪些方式?

  1. byName:根据Bean名称注入对象依赖项。@Resource默认按byName自动注入。

  2. byType:根据类类型注入对象依赖项。@AutoWried默认按byType自动注入。

  3. constructor :存在单个实例则优先按类型进行参数匹配;当存在多个相同类型的实例时,优先按名称匹配。

7.@Component和@Bean的区别是什么?

  • @Component 注解作用于类,而@Bean注解作用于方法(@Bean需要配合@Configuration使用)。

  • @Bean 注解比 @Component 注解更加灵活,当需要将第三方类装配到 Spring 容器中,因为没办法源代码上添加@Component注解,只能使用@Bean 注解的方式。

8.@Autowired和@Resource的区别?

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。

  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。

  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。

9.Bean的作用域

(1)singleton:单例,Spring中的Bean默认都是单例的。

(2)prototype:每次请求都会创建一个新的Bean实例。

(3)request:每一次HTTP请求都会产生一个新的Bean,该Bean仅在当前HTTP request内有效。

(4)session:每一次HTTP请求都会产生一个新的Bean,该Bean仅在当前HTTP session内有效。

(5)application:全局session作用域。

10.Bean生命周期

img

  1. 调用Bean的构造方法创建Bean

  2. 通过反射调用setter方法进行属性的依赖注入

  3. 如果Bean实现了BeanNameAware接口,Spring将调用setBeanName(),设置 Bean的name(xml文件中Bean标签的id)

  4. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()把Bean factory设置给Bean

  5. 如果存在BeanPostProcessor,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法,在Bean初始化前对其进行处理

  6. 如果Bean实现了InitializingBean接口,Spring将调用它的afterPropertiesSet方法,然后调用xml定义的 init-method 方法,两个方法作用类似,都是在初始化 Bean 的时候执行

  7. 如果存在BeanPostProcessor,Spring将调用它们的postProcessAfterInitialization(后初始化)方法,在Bean初始化后对其进行处理

  8. Bean初始化完成,供应用使用,这里分两种情况:

  • 8.1 如果Bean为单例的话,那么容器会返回Bean给用户,并存入缓存池。如果Bean实现了DisposableBean接口,Spring将调用它的destory方法,然后调用在xml中定义的 destory-method方法,这两个方法作用类似,都是在Bean实例销毁前执行。
  • 8.2 如果Bean是多例的话,容器将Bean返回给用户,剩下的生命周期由用户控制。

11.AOP是什么?

AOP是面向切面编程,能够将那些与业务无关,却为业务模块所共同调用的逻辑(如事务处理、日志、权限等)封装起来,以减少系统的重复代码,降低模块间的耦合度,并有利于未来的维护和扩展。

12.SpringAOP实现原理

SpringAOP是基于动态代理实现的,动态代理是有两种,一种是jdk动态代理,一种是cglib动态代理;

  • jdk动态代理是原理是利用反射来实现的,需要调用反射包下的Proxy类的newProxyInstance方法来返回代理对象,这个方法中有三个参数,分别是用于加载代理类的类加载器,被代理类实现的接口的class数组和一个用于增强方法的InvocationHandler实现类。

  • cglib动态代理原理是利用asm开源包来实现的,是把被代理类的class文件加载进来,通过修改它的字节码生成子类来处理

13.jdk动态代理和cglib动态代理的区别?

jdk动态代理要求被代理类必须有实现的接口,生成的动态代理类会和代理类实现同样的接口;cglib动态代理则不同,生成的动态代理类会继承被代理类。Spring默认使用jdk动态代理,当被代理的类没有接口时就使用cglib动态代理

14.AOP相关术语

目标(Target):被通知的对象
代理(Proxy):向目标对象应用通知之后创建的代理对象
连接点(JoinPoint):目标对象的所属类中,定义的所有方法均为连接点
切入点(Pointcut):被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点)
通知(Advice):增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情
切面(Aspect):切入点(Pointcut)+通知(Advice)
Weaving(织入):将通知应用到目标对象,进而生成代理对象的过程动作

15.AOP通知类型有哪些?

Before(前置通知):目标对象的方法调用之前触发

After (后置通知):目标对象的方法调用之后触发

AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发

AfterThrowing(异常通知):目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。

Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法

16.Spring事务原理?

Spring事务有编程式声明式,我们一般使用声明式,在某个方法上增加@Transactional注解,这个方法中的sql会统一成功或失败。

原理

当一个方法加上@Transactional注解,Spring会基于这个类生成一个代理对象并将这个代理对象作为Bean,当使用这个Bean中的方法时,如果存在@Transactional注解,就会将事务自动提交设为false,然后执行方法,执行过程没有异常则提交,有异常则回滚、

17.Spring事务失效场景

  • 事务方法所在的类没有加载到容器中
  • 业务自己捕获了异常,事务会认为程序正常秩序
  • 方法使用 final 或 static关键字
  • 事务方法不是public类型
  • 同一类中,一个没有添加事务的方法调用另外以一个添加事务的方法,事务不生效
  • Spring事务默认只回滚运行时异常,可以用rollbackfor属性设置

18.Spring事务的隔离级别

default:默认级别,使用数据库自定义的隔离级别

其它四种隔离级别与MySQL一样

19.Spring事务的传播行为

  • PROPAGATION_REQUIRED:支持当前事务,如果不存在,则新启一个事务
  • PROPAGATION_MANDATORY:支持当前事务,如果不存在,则抛出异常
  • PROPAGATION_SUPPORTS: 支持当前事务,如果不存在,则以非事务方式执行
  • PROPAGATION_REQUIRES_NEW:不支持当前事务,创建一个新事物
  • PROPAGATION_NEVER: 不支持当前事务,如果已存在事务就抛异常
  • PROPAGATION_NOT_SUPPORTED: 不支持当前事务,始终以非事务方式执行
  • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别

使用PROPAGATION_REQUIRES_NEW时,内层事务与外层事务是两个独立的事务。一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。

使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。

20.单例Bean是线程安全的吗?

Spring的默认Bean作用域是单例的,单例的Bean不是线程安全的,但是开发中大部分的Bean都是无状态的,不具备存储功能,比如controller、service、dao,他们不需要保证线程安全。

如果要保证线程安全,可以将Bean的作用域改为prototype

另外还可以采用ThreadLocal来解决线程安全问题。ThreadLocal为每个线程保存一个副本变量,每个线程只操作自己的副本变量。

21.循环依赖是什么,怎么解决的?

循环依赖就是在创建 A 实例的时候里面包含着 B 属性实例,所以这个时候就需要去创建 B 实例,而创 建 B 实例过程中也包含着 A 实例。 这样 A 实例还在创建的过程当中,所以就导致 A 和 B 实例都创建不出来。

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

一级缓存:缓存经过完整的生命周期的Bean

二级缓存 :缓存未经过完整的生命周期的Bean

三级缓存:缓存的是ObjectFactory

我们实例化A之后,先将 A 放入三级缓存 ,这时要创建B,B要注入A就直接去三级缓存中查找,然后将取出的A对象放入二级缓存中,因为这个时候 A 还未经 过完整的生命周期所以不能放入一级缓存。当B创建完成,放入一级缓存,A 继续执行生命周期,当A完成了属性的注入后,就可以放入一级缓存了

22.Spring用过哪些重要的注解?

@Component,@Service,@Repository,@Controller 用于服务类

@Autowired 通过类型来实现自动注入Bean

@Qualifier 配合@Autowired实现根据name注入Bean。

@Scope 用于配置 Spring Bean 的范围

@Configuration,@ComponentScan,@Bean 用于基于 java 的配置

@Aspect,@Before,@After,@Around,@Pointcut 用于切面编程

23.SpringMVC工作原理

SpringMVC工作过程围绕着前端控制器DispatcherServlet,几个重要组件有HandleMapping(处理器映射器)、HandleAdapter(处理器适配器)、ViewResolver(试图解析器)

工作流程:

(1)DispatcherServlet接收用户请求将请求发送给HandleMapping

(2)HandleMapping根据请求url找到具体的handle和拦截器,返回给DispatcherServlet

(3)DispatcherServlet调用HandleAdapter,HandleAdapter执行具体的controller,并将controller返回的ModelAndView返回给DispatchServler

(4)DispatcherServlet将ModelAndView传给ViewResolver,ViewResolver解析后返回具体view

(5)DispatcherServlet根据view进行视图渲染,返回给用户

24.如何定义一个全局异常处理类?

创建一个全局异常处理类,这个类上添加@ControllerAdvice注解,然后定义用于捕捉不同异常类型的方法,在这些方法上添加@ExceptionHandler(value = 异常类型.class)和@ResponseBody注解,方法参数是HttpServletRequest和异常类型,然后将异常消息进行处理。

25.如何自定义异常类?

创建一个自定义异常类继承一个异常接口,类属性包括final类型的连续id、错误码、错误信息,再根据需求写构造方法。

26.SpringMVC中的拦截器和Servlet中的过滤器有什么区别?

拦截器是基于Java的反射机制的,而过滤器是基于函数回调。

拦截器不依赖于servlet容器,过滤器依赖于servlet容器。

拦截器只能对部分请求起作用,而过滤器则可以对几乎所有的请求起作用。

拦截器可以访问Spring容器上下文里的对象,而过滤器不能访问。

拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

27.SpringMVC常见注解

  1. @Controller:用于定义控制器类
  2. @ResponseBody:表示方法的返回结果直接写入HTTP response body中
  3. @PathVariable:获取路径参数
  4. @RequestParam:用在方法的参数前面
  5. @RequestBody:请求的json转化为Bean去接收
  6. @RestController:是@Controller和@ResponseBody的合集
  7. @RequestMapping:提供路由信息,负责URL到Controller中的具体函数的映射
  8. @GetMapping:是@RequestMapping(method = RequestMethod.GET)的缩写。
  9. @PutMapping:是@RequestMapping(method = RequestMethod.PUT)的缩写。
  10. @PostMapping:是@RequestMapping(method = RequestMethod.POST)的缩写。
  11. @DeleteMapping:是@RequestMapping(method = RequestMethod.DELETE)的缩写。
  12. @ControllerAdvice:统一处理异常。
  13. @ExceptionHandler:用在方法上表示遇到这个异常就执行以下方法。
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jm呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值