Spring面试题整理
Spring的核心容器模块
Spring 的核心容器模块是 Spring Framework 的基础,为其他模块提供了支撑。它主要负责管理 Spring 应用程序中的对象生命周期和依赖关系
Spring 的核心容器模块是 Spring Framework 的基础,为其他模块提供了支撑。它主要负责管理 Spring 应用程序中的对象生命周期和依赖关系。核心容器模块主要包括以下几个重要的部分:
*1. BeanFactory*
BeanFactory 是 Spring 核心容器的基础接口。它负责配置和管理 bean 的生命周期,支持依赖注入。BeanFactory 提供了以下一些特性:
*获取 bean:* 提供根据 bean 名称或类型查找 bean 的方法。
*依赖注入:* 支持通过构造函数、setter 方法和接口注入依赖对象。
*延迟加载:* 只有在请求 bean 时才会创建实例,这样可以减少启动时的内存开销。
*2. ApplicationContext*
ApplicationContext 是 BeanFactory 的一个扩展,提供了更丰富的功能。它是更高级的容器,通常情况下优先使用它。与 BeanFactory 相比,ApplicationContext 增加了以下功能:
*国际化支持:* 提供 MessageSource 接口,可以方便地管理国际化信息。
*事件传播:* 支持事件机制,允许 beans 之间进行事件发布和监听。
*AOP(面向切面编程)😗 可以配置事务管理、日志记录等横切关注点。
*与 Spring MVC 库的整合:* 提供了更便利的支持。
*3. 主要实现类*
*1. XmlApplicationContext*
通过 XML 配置文件加载 bean 定义,适合大多数场景。
*2. AnnotationConfigApplicationContext*
用于基于注解的配置,允许使用 Java 注解(如 @Configuration 和 @Component)来定义 bean。
*3. WebApplicationContext*
是 ApplicationContext 的一个子接口,专门针对 web 应用程序的环境,提供了更多的功能,适用于 Spring MVC。
*4**. Beans 定义*
Spring 核心容器允许通过不同方式定义 bean:
*XML 配置:* 传统的方式,通过 beans.xml 文件定义 bean。
*注解:* 使用 @Component, @Service, @Repository, @Controller 等注解来标识类为 Spring 管理的组件。
*Java Config:* 使用 @Configuration 和 @Bean 注解来定义和配置 bean。
*5. 依赖注入*
Spring 核心容器支持多种依赖注入方式:
*构造器注入:* 在构造函数中传递依赖的 bean 实例。
*Setter 方法注入:* 通过 setter 方法设置依赖的 bean。
*接口注入:* 通过实现特定接口来注入依赖。
*6. 生命周期管理*
Spring 核心容器提供了对 bean 生命周期的管理,包括:
(不只有这两点)
*初始化:* 在 Spring 创建 bean 之后,可以指定初始化方法,进行自定义的初始化操作。
*销毁:* 在容器关闭时,可以指定销毁方法,执行清理操作
IoC容器
IOC容器: 指代那些支持控制反转的框架或组件,它负责管理程序中的对象及其依赖关系。
BeanFactory和ApplicationContext都是
ApplicationContext:
预先初始化: 默认情况下,会在启动时创建所有单例 bean
JDK动态代理和CGLIB(动态代理)字节码生成技术
- JDK 动态代理
JDK 动态代理是 Java 语言中提供的动态代理机制,它只支持接口(即被代理对象必须实现至少一个接口)。
特点
只代理接口: 代理对象必须实现一个或多个接口。
性能较高: 由于使用 Java 本身的反射机制,相比 CGLIB,开销较小。
简洁: 代理对象与目标对象通过接口进行交互,增强模块的解耦性。
- CGLIB(Code Generation Library)
CGLIB 是一个功能强大的、高性能的 Java 字节码生成库,可以在运行时动态创建类和代理。
特点
支持类的代理: CGLIB 可以对没有接口的类进行代理,支持对普通类的增强。
生成子类: CGLIB 通过创建目标类的子类以实现代理,因此不能对 final 类和 final 方法进行代理(因为不能被继承)。
相对较慢: 所有代理类在运行时生成,开销相对较大,但仍然具有较好的性能。
JDK 动态代理:通过接口实现(轻量、高性能)。
CGLIB:通过生成子类实现(支持没有接口的类,功能更强大,但性能相对较低)
IOC实现机制
*依赖注入*
*IOC 容器:*
Spring 提供了 IoC 容器(如 ApplicationContext 和 BeanFactory),用于管理对象的生命周期和依赖关系。
BeanFactory:是 Spring IOC 的最基本的容器,负责创建和管理 bean 的生命周期,Lazy Loading。
ApplicationContext:在功能上更为强大,它扩展了 BeanFactory,提供了更多的功能,例如国际化支持、事件传播等。
*Bean 的定义和配置:*
Spring 中的对象称为 “bean”,它们的定义通常通过 XML 配置、Java 注解或 Java 配置类。
Bean 定义包括 Bean 的类、作用域(如 singleton、prototype)、生命周期回调等。
*反射机制:*
Spring IOC 实现的核心之一是利用 Java 的反射机制。在实例化对象时,Spring 可以动态地创建对象并注入依赖。
反射允许 Spring 在运行时获取类的信息,从而创建对象、调用方法和设置字段。
*自动装配:*
Spring 支持自动装配,以便根据类型或名称自动找到并注入依赖。可以通过注解(如 @Autowired)或 XML 配置实现。
BeanFactory和ApplicationContext的区别
*BeanFactory:*
是 Spring IoC 容器的最基本形式,主要用于创建和管理 Bean。
在内存使用上的效率较高,提供了延迟加载(Lazy Initialization)功能,即只有在需要使用 Bean 时才会创建它。
提供的功能相对简单,缺少许多高级特性。
*ApplicationContext:*
是 BeanFactory 的扩展,提供了更多的功能和特性,例如国际化支持、事件传播、对 AOP 的支持等。
支持更多的功能,例如注解支持(如 @Autowired)、消息资源处理、应用事件等。
默认情况下,ApplicationContext 会在创建容器时实例化所有 singleton Bean,而不是等到第一次访问时再创建(除非使用 @Lazy 注解)。
*Spring框架中的Bean线程非安全,因为Spring框架没有对单例Bean进行多线程封装处理*
哪些是重要的bean****生命周期方法? 你能重载它们吗?
初始化和销毁
bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct和@PreDestroy)。
什么是Spring的内部bean?什么是Spring inner beans?
在Spring框架中,当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean通常是匿名的
<bean id="outerBean" class="com.example.OuterBean">
<property name="innerBean">
<bean class="com.example.InnerBean">
<property name="someProperty" value="someValue"/>
</bean>
</property>
</bean>
Bean装配
Bean 的装配(Bean Wiring)是指将不同的 Bean 组合在一起,以便它们能够相互协作和使用。通过装配,可以将一个 Bean 的实例注入到另一个 Bean 中
自动装配
自动装配(Autowiring)是 Spring 框架中的一个特性,它允许 Spring 容器在不显式地定义 Bean 依赖关系的情况下,自动处理和注入 Bean 的依赖。
自动装配方式
*按类型自动装配(byType):*
Spring 根据 Bean 的类型来查找依赖。
如果容器中有多个同类型的 Bean,会抛出异常,除非使用 @Qualifier 指定具体的 Bean。
<bean id="myBean" class="com.example.MyBean" autowire="byType"/>
*按名称自动装配(byName):*
Spring 根据 Bean 的名称查找依赖。
如果找到了与属性名称相同的 Bean,则自动装配。
<bean id="myBean" class="com.example.MyBean" autowire="byName"/>
*构造函数自动装配(constructor):*
Spring 使用 Bean 的构造函数参数的类型来查找依赖。
根据构造函数的参数类型进行匹配和注入。
<bean id="myBean" class="com.example.MyBean" autowire="constructor"/>
*使用注解:*
在 Java 类中使用 @Autowired 注解来标记要自动装配的字段、构造函数或方法。
结合 @Qualifier 指定具体的 Bean。
public class MyBean {
@Autowired
private DependencyBean dependency;
}
@Autowired注解自动装配的过程
在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
@Component、@Controller、@Repository、@Service有何区别
*1. @Component*
用途:这是一个泛用的注解,用于将一个类标识为 Spring 的组件,意味着这个类可以被 Spring 容器识别和管理。
应用场景:当一个类不适合特别的角色(如控制器、服务或数据访问对象)时,可以使用 @Component。
import org.springframework.stereotype.Component;
@Component
public class MyGenericComponent {
// ...
}
*2. @Controller*
用途:专门用于标识处理请求的控制器类,通常与 MVC(模型-视图-控制器)架构一起使用。
应用场景:当类负责接收用户请求,并且返回视图或数据时,应该使用 @Controller。Spring 会将该类中的方法映射到 HTTP 请求。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MyController {
@RequestMapping("/home")
public String home() {
return "home"; // 返回视图名
}
}
*3. @Service*
用途:用于标识服务层组件,通常用于业务逻辑和服务处理。
应用场景:当类提供与业务逻辑相关的功能,并且一般涉及多个 DAO(数据访问对象)时,使用 @Service。
import org.springframework.stereotype.Service;
@Service
public class MyService {
public void performService() {
// 业务逻辑
}
}
*4. @Repository*
用途:用于标识数据访问层组件,负责与数据库或数据源进行交互。
应用场景:当类中包含了对数据层的访问逻辑时,使用 @Repository。Spring 会自动处理数据访问异常的转换(如将技术异常转换为 Spring 的统一异常)。
import org.springframework.stereotype.Repository;
@Repository
public class MyRepository {
public void save(Object obj) {
// 数据库保存逻辑
}
}
@Autowired和@Resource的区别
*@Autowired:*
这是 Spring 框架提供的注解,属于 Spring 的构件。
默认情况下,使用按类型注入。如果容器中有多个同类型的 Bean,将会抛出异常。可以通过 @Qualifier 注解来指定具体的 Bean。
例如:
@Autowired
private MyService myService; //按类型注入
*@Resource:*
这是 Java EE 的标准注解,属于 JDK,它主要用于资源的注入,可以按名称或按类型进行依赖注入。
默认情况下,先按名称查找 Bean,如果找不到再按类型查找。
如果有同名的 Bean,且希望按名称注入,可以直接使用同名属性来注入。
例如:
@Resource
private MyService myService; //按名称注入
@Qualifier作用
用于在依赖注入时指明具体要注入哪一个 Bean。当有多个同类型的 Bean 存在时,Spring 需要明确知道哪个 Bean 应该被注入,而 @Qualifier 提供了这种能力。
@RequestMapper作用
是 Spring MVC 中用于处理 HTTP 请求的一个注解,它可以应用于类和方法上。@RequestMapping 的主要作用是将 HTTP 请求映射到对应的处理方法,以便于处理器能够响应特定的 URL。
Spring支持的事务管理类型
*编程式事务管理*
概述:编程式事务管理是直接在代码中通过编程的方式来控制事务的行为。开发者需要手动开启、提交或回滚事务。
使用场景:适合需要高度灵活性或自定义事务边界的场景。
*声明式事务管理*
概述:声明式事务管理允许开发者通过配置的方式来声明事务的边界。通常使用 AOP(面向切面编程)来实现,开发者不需要修改业务代码。
使用场景:适合大多数应用场景,特别是在进行简单的 CRUD 操作时。
示例:
使用注解:
import org.springframework.transaction.annotation.Transactional;
@Service
public class MyService {
@Transactional
public void performTransaction() {
// 执行数据库操作
}
}
使用 XML 配置:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.example.service..*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>