前沿
spring是java开发日常使用最多的框架,理解并应用好spring是基础核心能力。第一版略显粗糙,持续更新中。
1.什么是Spring循环依赖。
Spring循环依赖指的是两个或多个Bean之间相互依赖,形成一个环状依赖的情况。简单来说,就是A依赖B,B依赖C,C依赖A,这样就形成了一个循环依赖的环。
Spring循环依赖通常会导致Bean无法正确地被实例化,从而导致应用程序无法正常启动或者出现异常。因此,Spring循环依赖是一种需要尽量避免的情况。
Spring循环依赖的解决方法
为了解决Spring循环依赖问题,我们可以采取以下几种方法:
- 构造函数注入: 在构造函数注入中,Spring会检查循环依赖,并在发现循环依赖时抛出异常,避免死循环。
- 使用@Lazy注解: @Lazy注解可以延迟Bean的实例化,从而避免循环依赖的问题。
- 使用setter方法
Spring是如何解决Bean的循环依赖?
Spring是如何解决的循环依赖: 采用三级缓存解决的 就是三个Map ; 关键: 一定要有一个缓存保存它的早期对象作为死循环的出口
一级缓存singletonObjects存放可以使用的单例。
二级缓存earlySingletonObjects存放的是早期的bean,即半成品,此时还无法使用。
三级缓存singletonFactories是一个对象工厂,用于创建对象并放入二级缓存中。同时,如果对象有Aop代理,则对象工厂返回代理对象。
2.BeanPostProcessor作用和使用场景
BeanPostProcessor
的主要作用是允许对新创建的bean实例进行一些处理,或者是对bean的某些属性进行修改。具体来说,它可以用于以下几种情况:
- 自定义初始化逻辑:可以在bean初始化之前或之后添加一些自定义逻辑,比如日志记录或性能监控。
- 代理对象:可以通过AOP(面向方面编程)技术为bean创建代理对象,在方法调用前后添加切面逻辑。
- 依赖注入后处理:在Spring自动注入依赖之后,可以进行进一步的处理,比如检查某些依赖是否已经注入,或者根据注入的依赖进行一些初始化操作。
- 属性修改:在bean完全初始化之前,可以修改bean的某些属性,或者设置某些默认值。
代码实现(自定义初始化逻辑)
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class CustomInitializationBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Before Initialization : " + beanName);
// 这里可以添加自定义的初始化逻辑
if (bean instanceof MyBean) {
// 对特定bean的处理
((MyBean) bean).customInitBefore();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("After Initialization : " + beanName);
// 这里可以添加自定义的初始化逻辑
if (bean instanceof MyBean) {
// 对特定bean的处理
((MyBean) bean).customInitAfter();
}
return bean;
}
}
public class MyBean {
private String name;
// getter和setter方法
public void customInitBefore() {
System.out.println("Custom Init Before: " + name);
// 在初始化之前的自定义逻辑
}
public void customInitAfter() {
System.out.println("Custom Init After: " + name);
// 在初始化之后的自定义逻辑
}
}
3.Spring中bean的初始化流程
Spring框架中,bean的创建过程是一个复杂且多步骤的过程,涉及到多个阶段和各种机制。以下是Spring中bean创建过程的详细步骤:
- Bean Definition Loading
Spring通过配置文件(XML、Java配置类、注解等)加载bean定义(BeanDefinition),这些定义描述了bean的配置信息,包括bean的类名、作用域、依赖关系等。
- Bean Definition Registry
加载的bean定义会被注册到BeanDefinitionRegistry
中。Spring使用不同的BeanDefinitionReader
来解析配置并将bean定义注册到BeanFactory
中。
- Bean Instantiation
当Spring容器需要一个bean的实例时,它会通过InstantiationStrategy
实例化bean。这时只创建了对象,还没有进行依赖注入。
- Populate Bean Properties (Dependency Injection)
Spring会通过依赖注入(DI)机制将需要的依赖注入到bean中。可以使用以下几种方式进行注入:
- 构造器注入
- Setter方法注入
- 注解(如
@Autowired
、@Inject
、@Resource
)
- BeanPostProcessor - Before Initialization
在bean初始化之前,Spring会调用所有注册的BeanPostProcessor
的postProcessBeforeInitialization
方法,对bean进行处理。
- Bean Initialization
- 如果bean实现了
InitializingBean
接口,Spring会调用其afterPropertiesSet
方法。 - 如果在bean定义中指定了init-method,Spring会调用该自定义初始化方法。
- BeanPostProcessor - After Initialization
在bean初始化之后,Spring会调用所有注册的BeanPostProcessor
的postProcessAfterInitialization
方法,对bean进行进一步处理。
- Bean Ready for Use
至此,bean已经完全初始化并可以被应用程序使用。
- Bean Destruction (For Singleton and Prototype Scopes)
当Spring容器关闭时,会对singleton作用域的bean进行销毁处理。
- 如果bean实现了
DisposableBean
接口,Spring会调用其destroy
方法。 - 如果在bean定义中指定了destroy-method,Spring会调用该自定义销毁方法。
4.什么是Spring IOC?
Spring IOC(Inversion of Control)是Spring框架的核心特性之一,翻译为"控制反转"。它是一种设计原则,用于将对象的创建和依赖关系的管理从应用程序代码中分离出来,由Spring容器(也称为IOC容器)负责管理。
核心概念
- 控制反转(Inversion of Control)
控制反转的基本思想是将对象的控制权从应用程序代码中移交给Spring容器。传统的编程方式中,对象是通过代码直接创建和管理的,而在IOC容器中,对象的创建和依赖关系的注入都是由容器来管理的。
- 依赖注入(Dependency Injection,DI)
依赖注入是实现控制反转的一种方式。它通过构造函数、Setter方法或字段注入将依赖关系注入到对象中,而不是由对象自己创建或查找依赖。
主要优点
- 解耦:通过依赖注入,对象之间的耦合度大大降低,使代码更容易维护和测试。
- 易于测试:由于依赖是注入的,可以轻松地使用Mock对象进行单元测试。
- 灵活性:可以通过配置文件或注解灵活地配置和管理对象的依赖关系。
5.Spring Bean的生命周期
-
实例化(Instantiation):Spring容器通过反射机制创建bean的实例。
-
属性注入(Populating Bean Properties):Spring容器将配置中的属性(例如通过XML配置、注解或Java配置类)注入到bean的相应属性中。
-
设置BeanName (Setting Bean Name):如果bean实现了
BeanNameAware
接口,Spring容器会调用setBeanName
方法,将该bean在容器中的名称传递给它。 -
设置Bean工厂 (Setting Bean Factory):如果bean实现了
BeanFactoryAware
接口,Spring容器会调用setBeanFactory
方法,将BeanFactory
实例传递给它。 -
设置ApplicationContext (Setting ApplicationContext):如果bean实现了
ApplicationContextAware
接口,Spring容器会调用setApplicationContext
方法,将ApplicationContext
实例传递给它。 -
Bean的初始化(Bean Initialization):这一阶段包括两部分:
- 调用
BeanPostProcessor
的postProcessBeforeInitialization
方法 :如果bean实现了BeanPostProcessor
接口,Spring容器会在bean初始化之前调用它的postProcessBeforeInitialization
方法。 - 调用自定义的初始化方法 :Spring容器会调用bean的初始化方法。如果bean实现了
InitializingBean
接口,会调用其afterPropertiesSet
方法。此外,如果bean在配置中指定了init-method属性,也会调用这个自定义初始化方法。
- 调用
-
调用
BeanPostProcessor
的postProcessAfterInitialization
方法 :如果bean实现了BeanPostProcessor
接口,Spring容器会在bean初始化之后调用它的postProcessAfterInitialization
方法。 -
Bean的就绪状态(Bean Ready):此时bean已经完全初始化并且可以使用。
-
Bean的销毁(Bean Destruction):当Spring容器关闭时,会执行bean的销毁过程。这一阶段包括:
- 调用
DisposableBean
的destroy
方法 :如果bean实现了DisposableBean
接口,Spring容器会调用它的destroy
方法。 - 调用自定义的销毁方法:如果bean在配置中指定了destroy-method属性,Spring容器会调用这个自定义销毁方法。
- 调用
6.Spring的事物传播模型?
Spring事务传播(Transaction Propagation)定义了一个事务中方法的执行方式,以及是否应该加入到现有事务中。Spring提供了多种事务传播行为,以满足不同的业务需求。以下是Spring支持的主要事务传播行为:
REQUIRED
这是默认的传播行为。如果当前存在一个事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
REQUIRES_NEW
每次都会新建一个事务。如果当前存在事务,则挂起该事务,直到新事务完成。
SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
NOT_SUPPORTED
总是以非事务方式执行。如果当前存在事务,则挂起该事务,直到该方法执行完成。
NEVER
总是以非事务方式执行。如果当前存在事务,则抛出异常。
MANDATORY
必须在一个已有事务中运行。如果当前没有事务,则抛出异常。
NESTED
如果当前存在事务,则在嵌套事务中执行。如果当前没有事务,则创建一个新的事务。嵌套事务在内部使用保存点(savepoint),这意味着它们可以独立于外部事务进行回滚。