Day09
1. Spring的Bean的生命周期
- 实例化(Instantiation):Spring 容器启动时,根据配置扫描 Bean 定义,使用构造函数创建 Bean 实例(默认是无参构造)。
- 属性填充(Populate Properties):Bean 实例创建后,Spring 将配置中的属性值注入到 Bean 对应的字段中(依赖注入)。
- BeanNameAware:使用
setBeanName(String name)
方法注入当前 Bean 的名称。- BeanFactoryAware:使用
setBeanFactory(BeanFactory factory)
方法注入当前 Bean 所在的 BeanFactory 容器实例。- ApplicationContextAware:使用
setApplicationContext(ApplicationContext context)
方法注入当前 Bean 所在的应用上下文(ApplicationContext)。- BeanPostProcessor(初始化前):使用
postProcessBeforeInitialization(Object bean, String beanName)
方法初始化方法执行前的处理逻辑。可用于包装、代理等。- 初始化(Initialization):通过实现接口
InitializingBean.afterPropertiesSet()
方法或者配置 init-method:<bean init-method="initMethodName"/>
两种方式,进行 Bean 初始化逻辑,比如打开连接池、加载配置等。- BeanPostProcessor(初始化后):使用
postProcessAfterInitialization(Object bean, String beanName)
方法初始化方法执行后的扩展处理(如 AOP 代理)。- 就绪使用(Ready to Use):Bean 已完全初始化,可以被应用程序正常使用。
- 销毁:通过实现接口
DisposableBean.destroy()
或者配置 destroy-method:<bean destroy-method="destroyMethodName"/>
两种方式,容器关闭时调用,用于释放资源、关闭连接等。
2. Bean是否单例?
在 Spring 中,Bean 默认是单例模式,即每个 Bean 在整个 Spring 容器中只会被实例化一次,并存储在容器的缓存中。这样,当应用程序中多次请求同一个 Bean 时,Spring 会返回同一个实例,从而提高了性能和资源利用率。
Spring 也提供了对多例模式的支持。若在定义 Bean 时将 score 属性设置为“prototype”,则每次从容器中获取该 Bean 时,Spring 都会创建一个新的实例。这种模式适用于具有状态的 Bean 或线程不安全的场景。
注意:单例 Bean 若持有可变状态,则在多线程环境下可能引发线程安全问题,因此在设计时要格外小心,必要时应使用线程安全的设计或考虑改为多例模式。
3. Bean的单例和非单例,生命周期是否一样?
不一样,Spring Bean 的生命周期完全由 IOC 容器控制。Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 Bean,Spring 在创建好交给使用者只会,则不会再管理后续的生命周期。
上面的生命周期是单例的。而多例的生命周期:Spring 只负责创建、依赖注入、初始化,不负责销毁(需手动销毁或通过自定义逻辑管理)。
4. Spring容器里存的是什么?
在 Spring 容器中,存储的各类 Bean 对象及其元数据信息。Spring 容器让应用启动时会根据配置(如注解、XML 或 JavaConfig)加在 Bean 定义,负责创建 Bean 实例、注入依赖、管理生命周期(包括初始化与销毁)等操作。对于单例 Bean,Spring 会将其实例缓存起来以供全局复用;而对于原型 Bean,Spring 仅负责创建,不再管理后续生命周期。除了 Bean 实例本身,容器还维护了 Bean 的配置信息、单例缓存、时间发布机制等,是整个 IOC 控制反转的核心管理中心。
5. Bean注入和XML注入最终得到了相同的效果,它们在底层是怎么做的?
XML注入:使用 XML 文件进行 Bean 注入时,Spring 在启动时会读取 XML 配置文件。步骤如下:
- Bean 定义解析:Spring 容器通过
XmlBeanDefinitionReader
类解析 XML 配置文件,读取其中的<bean>
标签以获取 Bean 的定义信息。- 注册 Bean 定义:解析后的 Bean 信息被注册到
BeanDefinitionRegistry
(如DefaultListableBeanFactory
)中,包括 Bean 的类、作用域、依赖关系、初始化和销毁方法等。- 实例化和依赖注入:当应用程序请求某个 Bean 时,Spring 容器会根据已经注册的 Bean 定义:首先使用反射机制创建该 Bean 的实例,然后根据 Bean 定义中的配置,通过 setter 方法、构造函数或方法注入所需的依赖 Bean。、
注解注入:使用注解进行 Bean 注入时,Spring 的处理过程如下:
- 类路径扫描:当 Spring 容器启动时,它首先会进行类路径扫描,查找带有特定注解(如
@Component
、@Service
、@Repository
和@Controller
)的类。- 注册 Bean 定义:找到的类会被注册到
BeanDefinitionRegistry
中,Spring 容器将为其生成 Bean 定义信息。这通常通过AnnotatedBeanDefinitionReader
类来实现。- 依赖注入:与 XML 注入类似,Spring 在实例化 Bean 时,也会检查字段上是否有
@Autowired
、@Inject
或@Resource
注解。如果有,Spring 会根据注解的信息进行依赖注入。尽管使用的方式不同,但 XML 注入和注解注入在底层的实现机制是相似的,主要体现在以下几个方面:
- BeanDefinition:无论是 XML 还是注解,最终都会生成 BeanDefinition 对象,并存储在同一个 BeanDefinitionRegistry 中。
- 后处理器:Spring 提供了多个 Bean 后处理器(如
AutowiredAnnotationBeanPostProcessor
),用于处理注解(如@Autowired
)的依赖注入。对于 XML,Spring 也有相应的后处理器来处理 XML 配置的依赖注入。- 依赖查找:在依赖注入时,Spring 容器会通过 ApplicationContext 中的 BeanFactory 方法来查找和注入依赖,无论是通过 XML 还是注解,都会调用类似的查找方法。