Spring 面试集
基于Spring Framework 4.x 总结的常见面试题,系统学习建议还是官方文档走起:https://spring.io/projects/spring-framework#learn
一、一般问题
开发中主要使用 Spring 的什么技术 ?
- IOC 容器管理各层的组件
- 使用 AOP 配置声明式事务
- 整合其他框架
Spring有哪些优点?
- 轻量级:Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB。
- 控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。
- 面向切面编程(AOP):Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
- 容器:Spring包含并管理应用程序对象的配置及生命周期。
- MVC框架:Spring的web框架是一个设计优良的web MVC框架,很好的取代了一些web框架。
- 事务管理:Spring对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口。
- 异常处理:Spring提供一个方便的API将特定技术的异常(由JDBC, Hibernate, 或JDO抛出)转化为一致的、Unchecked异常。
Spring模块
简述 AOP 和 IOC 概念
AOP:Aspect Oriented Program, 面向(方面)切面的编程;Filter(过滤器)也是一种 AOP. AOP 是一种新的 方法论, 是对传统 OOP(Object-OrientedProgramming, 面向对象编程) 的补充. AOP 的主要编程对象是切面(aspect),而切面模块化横切关注点.可以举例通过事务说明.
IOC:Invert Of Control, 控制反转. 也称为 DI(依赖注入)其思想是反转资源获取的方向. 传统的资源查找方式要求组件向容器发起请求查找资源.作为回应, 容器适时的返回资源. 而应用了 IOC 之后, 则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源. 这种行为也被称为查找的被动形式
二、依赖注入
IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。
将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。
什么是 Spring IOC 容器?
Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。
什么是依赖注入?
依赖注入(DI,Dependency Injection)是在编译阶段尚未知所需的功能是来自哪个的类的情况下,将其他对象所依赖的功能对象实例化的模式。这就需要一种机制用来激活相应的组件以提供特定的功能,所以依赖注入是控制反转的基础。否则如果在组件不受框架控制的情况下,框架又怎么知道要创建哪个组件?
依赖注入有以下三种实现方式:
- 构造器注入
- Setter方法注入(属性注入)
- 接口注入
Spring 中有多少种 IOC 容器?
在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前,必须对它进行实例化。只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用
Spring 提供了两种类型的 IOC 容器实现
-
BeanFactory:IOC 容器的基本实现
-
ApplicationContext:提供了更多的高级特性,是 BeanFactory 的子接口
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory;
无论使用何种方式, 配置文件是相同的。
BeanFactory 和 ApplicationContext 区别
BeanFactory | ApplicationContext |
---|---|
懒加载 | 即时加载 |
它使用语法显式提供资源对象 | 它自己创建和管理资源对象 |
不支持国际化 | 支持国际化 |
不支持基于依赖的注解 | 支持基于依赖的注解 |
ApplicationContext
ApplicationContext 的主要实现类:
- ClassPathXmlApplicationContext:从类路径下加载配置文件
- FileSystemXmlApplicationContext: 从文件系统中加载配置文件
- ConfigurableApplicationContext 扩展于 ApplicationContext,新增加两个主要方法:refresh() 和 close(), 让 ApplicationContext具有启动、刷新和关闭上下文的能力
- WebApplicationContext 是专门为 WEB 应用而准备的,它允许从相对于 WEB 根目录的路径中完成初始化工作
- ApplicationContext 在初始化上下文时就实例化所有单例的 Bean
从 IOC 容器中获取 Bean
- 调用 ApplicationContext 的 getBean() 方法
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
helloWorld.hello();
列举 IoC 的一些好处
- 它将最小化应用程序中的代码量;
- 它将使您的应用程序易于测试,因为它不需要单元测试用例中的任何单例或 JNDI 查找机制;
- 它以最小的影响和最少的侵入机制促进松耦合;
- 它支持即时的实例化和延迟加载服务
Spring IoC 的实现机制
Spring 中的 IoC 的实现原理就是工厂模式加反射机制,示例:
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("priv.starfish.spring.Apple");
if(f!=null){
f.eat();
}
}
}
三、Beans
什么是 Spring Beans?
- 它们是构成用户应用程序主干的对象
- Bean 由 Spring IoC 容器管理
- 它们由 Spring IoC 容器实例化,配置,装配和管理
- Bean 是基于用户提供给容器的配置元数据创建
Spring 提供了哪些配置方式?
-
基于 xml 配置
bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:
<bean id="studentbean" class="org.edureka.firstSpring.StudentBean"> <property name="name" value="Edureka"></property> </bean>
-
基于注解配置
您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配置文件中启用它。例如:
<beans> <context:annotation-config/> <!-- bean definitions go here --> </beans>
-
基于 Java API 配置
Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。
-
@Bean 注解扮演与
<bean/>
元素相同的角色。 -
@Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。
-
例如:
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
Spring Bean的作用域?
-
在 Spring 中, 可以在 <bean> 元素的 scope 属性里设置 Bean 的作用域。
-
默认情况下,Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例,整个 IOC 容器范围内都能共享该实例:所有后续的
getBean()
调用和 Bean 引用都将返回这个唯一的 Bean 实例。该作用域被称为 singleton,它是所有 Bean 的默认作用域。
Spring 容器中的 bean 可以分为 5 个范围。所有范围的名称都是自说明的,但是为了避免混淆,还是让我们来解释一下:
- singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean的实例,单例的模式由bean factory自身来维护。
- prototype:原型范围与单例范围相反,为每一个bean请求提供一个实例。
- request:每次HTTP请求都会创建一个新的bean,该作用于仅适用于WebApplicationContext环境,在请求完成以后,bean会失效并被垃圾回收器回收。
- Session:同一个HTTP Session 共享一个bean,不同的 HTTP Session使用不同的bean。该作用于仅适用于WebApplicationContext环境,在session过期后,bean会随之失效。
- global-session:全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话
全局作用域与Servlet中的session作用域效果相同。
Spring bean 容器的生命周期是什么样的?
Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务。
Spring bean 容器的生命周期流程如下:
- Spring 容器根据配置中的 bean 定义实例化 bean;
- Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置;
- 如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName();
- 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory();
- 与上面的类似,如果实现了其他
*.Aware
接口,就调用相应的方法; - 如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法;
- 如果为 bean 指定了 init 方法(
<bean>
的 init-method 属性),那么将调用它; - 最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法;
- 如果 bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory();
- 如果为 bean 指定了 destroy 方法(
<bean>
的 destroy-method 属性),那么将调用它
在 bean 初始化时会经历几个阶段,要与容器对 bean 生命周期的管理交互,可以实现 InitializingBean
和 DisposableBean
接口。容器对前者调用 afterPropertiesSet()
,对后者调用 destroy()
,以允许 bean 在初始化和销毁 bean 时执行某些操作。
官方不建议使用这两个接口,而是建议使用 @PostConstruct
和 @PreDestroy
,或者 XML 配置中使用 init-method
和destroy-method
属性
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization work
}
}
等价于
public class AnotherExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
}
}
Spring Bean生命周期回调——初始化回调和销毁回调方法
实现 Bean 初始化回调和销毁回调各有三种方法,一是实现接口方法,二是在XML配置,三是使用注解
- 使用注解
@PostConstruct
和@PreDestroy
- 实现
InitializingBean
和DisposableBean
接口 - XML 中配置
init-method
和destroy-method
在一个 bean 中,如果配置了多种生命周期回调机制,会按照上边从上到下的次序调用
在 Spring 中如何配置 Bean?
Bean 的配置方式: 通过全类名 (反射)、 通过工厂方法 (静态工厂方法 & 实例工厂方法)、FactoryBean
什么是 Spring 装配
当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配,装配是创建应用对象之间协作关系的行为。 Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。
依赖注入的本质就是装配,装配是依赖注入的具体行为。
注入是实例化的过程,将创建的bean放在Spring容器中,分为属性注入(setter方式)、构造器注入
什么是bean自动装配?
Spring 容器可以自动配置相互协作 beans 之间的关联关系。这意味着 Spring 可以自动配置一个 bean 和其他协作bean 之间的关系,通过检查 BeanFactory 的内容里有没有使用< property>元素。
在Spring框架中共有5种自动装配,让我们逐一分析
-
no:这是Spring框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在beanautowire属性里指定自动装配的模式
-
byName:该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
-
byType:该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时,容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
-
constructor:构造器的自动装配和byType模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
-
autodetect:Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配
自动装配有什么局限?
- 基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。
- 装配依赖中若是出现匹配到多个bean(出现歧义性),装配将会失败
通过注解的方式配置bean | 什么是基于注解的容器配置
组件扫描(component scanning): Spring 能够从 classpath下自动扫描, 侦测和实例化具有特定注解的组件。
特定组件包括:
- @Component:基本注解, 标识了一个受 Spring 管理的组件
- @Respository:标识持久层组件
- @Service:标识服务层(业务层)组件
- @Controller: 标识表现层组件
对于扫描到的组件,,Spring 有默认的命名策略:使用非限定类名,,第一个字母小写。也可以在注解中通过 value 属性值标识组件的名称。
当在组件类上使用了特定的注解之后,,还需要在 Spring 的配置文件中声明 <context:component-scan>
:
-
base-package
属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类 -
当需要扫描多个包时, 可以使用逗号分隔
-
如果仅希望扫描特定的类而非基包下的所有类,可使用
resource-pattern
属性过滤特定的类,示例:<context:component-scan base-package="priv.starfish.front.web.controller" annotation-config="true" resource-pattern="autowire/*.class"/>
如何在 spring 中启动注解装配?
默认情况下,Spring 容器中未打开注解装配。因此,要使用基于注解装配,我们必须通过配置<context:annotation-config />
元素在 Spring 配置文件中启用它。
四、AOP
标签:容器,面试题,Spring,事务,面试,bean,AOP,注解 From: https://www.cnblogs.com/wind-xwj/p/17525446.html