1.Spring常见面试题
1.IOC
1.1 IOC概述
IOC(Inversion of Controller:控制反转)的思想是将原本在程序中手动创建对象的控制权,交给 Spring 框架管理。
为什么叫控制反转?
- 控制:对象创建(实例化、管理)的权利;
- 反转:控制权交给外部环境(Spring框架、IOC容器);
在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。
1.2 Spring Bean是什么
Bean 代指的就是那些被 IoC 容器所管理的对象。我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。
1.3 将类声明为Bean的注解
@Component
:通用的注解,可标注任意类为Spring
组件。如果一个 Bean 不知道属于哪个层,可以使用@Component
注解标注。@Repository
: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service
: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller
: 对应 Spring MVC 控制层,主要用于接受用户请求并调用Service
层返回数据给前端页面。
1.4 @Component注解和@Bean注解的区别
@Component
注解作用于类,而@Bean
注解作用于方法。@Component
通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用@ComponentScan
注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean
注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean
告诉了 Spring 这是某个类的实例,当我需要用它的时候再给我。@Bean
注解比@Component
注解的自定义性更强,而且很多地方我们只能通过@Bean
注解来注册 bean。比如当我们引用第三方库中的类需要装配到Spring
容器时,则只能通过@Bean
来实现。
1.5 @Autowired注解和@Resource注解的区别
- @Autowired注解是Spring提供的注解,@Resource是JDK提供的注解;
- @Autowired默认通过类型注入Bean,@Resource默认根据Bean名称注入Bean;
- 当接口存在多个实现类时,@Autowired和@Resource都需要通过Bean名称来注入Bean。@Autowaired可配合@Qualifier注解显示指定Bean名称,@Resource通过name属性显示指定Bean名称;
- @Autowired支持构造函数、方法、字段和参数上使用,@Resource主要用于字段和方法上的注入,不支持在构造函数和参数上使用;
1.6 Bean的作用域
Spring 中 Bean 的作用域通常有下面几种:
- singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
- prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续
getBean()
两次,得到的是不同的 Bean 实例。 - request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
- session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
- application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
- websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
1.7 Bean的线程安全吗
Spring中的Bean是否线程安全取决于作用域和状态。
以常用的作用域prototype和singleton为例,几乎所有场景的Bean作用域为singleton。在prototype作用域下,每次获取都会创建一个新的Bean,不存在资源竞争问题,因此也不存在Bean的线程安全问题。在Singleton作用域下,IOC容器只有唯一的Bean实例,可能存在资源竞争问题(取决于Bean是否有状态)。若有状态,则存在线程安全问题(有状态Bean是指包括可变的成员变量对象)。
大部分Bean无状态(没有定义可变的成员变量)(如Dao、Service),这种情况下,Bean线程安全。
对于有状态单例Bean的线程安全问题的解决方案:
- 在Bean中尽量避免定义可变的成员变量;
- 在类中定义一个ThreadLocal成员变量,将需要的可变的成员变量保存在ThreadLocal中(推荐使用);
1.8 Bean的生命周期
- Bean容器找到配置文件中Spring Bean的定义
- Bean容器利用Java Reflection API创建Bean的实例
- 若涉及属性值,则使用set()方法设置属性值
- 如果Bean实现了BeanXXXAware接口,调用setXXX()方法,传入XXX对象实例;如Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名称。Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象实例。Bean实现了BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象实例。
- 如果有加载该Bean的Spring相关BeanPostProcessor对象,则执行postProcessBeforeInitialization()方法。
- 如果Bean实现了InitailizingBean接口,执行afterPropertySet()方法。
- 若Bean配置文件的定义中有init-method属性,执行指定的方法。
- 如果有加载该Bean的Spring相关BeanPostProcessor对象,则执行postProcessAfterInitialization()方法。
- 当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。
- 当要销毁Bean的时候,配置文件的定义包含了destroy-method属性,则执行指定方法。
2.Spring注解
Spring 注解是用于在 Spring 框架中进行配置和管理的一种方便而强大的方式。通过使用注解,我们可以在应用程序中声明和配置各种组件、依赖关系、切面和行为,减少了传统配置方式的繁琐性和复杂性,提高了开发效率和可读性。
- 简化配置:使用注解定义和配置各种组件、依赖关系:
- 自动装配:使用注解自动识别和注入依赖关系,降低组件之间的耦合度;
- 依赖关系管理:通过@Component、@Service、@Controller注解将普通类标记为Spring的组件,方便容器对齐管理和维护;
- 切面和面向切面编程:通过@Aspect、@Around注解声明和定义切面和通知,实现横切关注点的集中管理和复用;
- 控制事务:通过Transactional注解,将事务逻辑应用于指定的方法或类,简化事务管理的配置和操作
- 配置属性:使用注解如@Value,可将外部属性注入到指定属性上,方便配置和管理。
参考链接
Spring常见面试题总结 | JavaGuide(Java面试 + 学习指南)