Spring 的奇幻起源:从 IoC 容器到 Bean 的魔法世界 (上):https://developer.aliyun.com/article/1456573
Bean 的作用域和生命周期管理
解析 Bean 的作用域和生命周期概念
在Spring框架中,理解Bean的作用域和生命周期是至关重要的,它们决定了Bean的创建、管理及销毁方式。本篇博客将深入探讨这两个概念,并通过示例代码帮助读者更好地理解Spring提供的各种Bean生命周期回调方法。
一、Bean的作用域(Scope)
在Spring中,Bean的作用域决定了容器如何新建Bean实例的规则。Spring提供了几种作用域:
- singleton:(默认作用域)容器中只存在一个共享的Bean实例,每次请求都返回同一个Bean实例。
- prototype:每次请求都会创建一个新的Bean实例。
- request:每次HTTP请求都会产生一个新的Bean,仅在Web应用中有效。
- session:在一个HTTP Session中,一个Bean定义对应一个实例。仅在Web应用中有效。
- application:在一个ServletContext生命周期内,一个Bean定义对应一个实例。仅在Web应用中有效。
示例代码:定义不同作用域的Bean
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration public class BeanScopeConfig { @Bean @Scope("singleton") public MyBean singletonBean() { return new MyBean(); } @Bean @Scope("prototype") public MyBean prototypeBean() { return new MyBean(); } }
二、Bean的生命周期
Bean的生命周期指的是从Bean的初始化到销毁的整个过程。在这个过程中,Spring容器提供了多个扩展点,允许在Bean的创建和销毁过程中加入自定义逻辑。
Bean生命周期的主要阶段:
- 实例化Bean:Spring容器首先调用构造函数或工厂方法来实例化Bean。
- 填充属性:Spring容器注入Bean所需要的依赖。
- 调用BeanNameAware的setBeanName():如果Bean实现了BeanNameAware接口,Spring容器将Bean的ID传给setBeanName方法。
- 调用BeanFactoryAware的setBeanFactory():如果Bean实现了BeanFactoryAware接口,Spring容器将调用setBeanFactory方法,传入BeanFactory。
- 调用ApplicationContextAware的setApplicationContext():如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext方法,传入ApplicationContext。
- 前置处理器Before Initialization:BeanPostProcessor的postProcessBeforeInitialization方法将被调用。
- 初始化:如果Bean实现了InitializingBean接口,Spring容器将调用afterPropertiesSet方法。另外,可以通过@Bean注解的initMethod指定初始化方法。
- 后置处理器After Initialization:BeanPostProcessor的postProcessAfterInitialization方法将被调用。
- Bean准备就绪:此时,Bean已经准备好被应用使用了。
- 销毁:当容器关闭时,如果Bean实现了DisposableBean接口,Spring容器将调用destroy方法。也可以通过@Bean注解的destroyMethod指定销毁方法。
示例代码:自定义Bean生命周期回调方法
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class MyLifecycleBean implements InitializingBean, DisposableBean { @Override public void afterPropertiesSet() throws Exception { // 初始化逻辑 System.out.println("MyLifecycleBean is initialized."); } @Override public void destroy() throws Exception { // 销毁逻辑 System.out.println("MyLifecycleBean is destroyed."); } }
通过实现InitializingBean
和DisposableBean
接口,我们可以在Bean的生命周期的特定时间点执行自定义逻辑。
Bean 的属性装配和自动装配
深入理解Spring Bean:属性、依赖与自动装配
在Spring框架中,Bean是构建应用程序的基石。它们不仅承载着数据和行为,还通过依赖关系与其他Bean相互作用。正确地管理Bean的属性和依赖关系,是实现高效、可维护Spring应用的关键。本篇博客将带你深入理解Bean的属性和依赖关系,并掌握Spring提供的属性配置和自动装配方式。
一、理解Bean的属性和依赖关系
Bean的属性
Bean的属性指的是Bean中的字段,这些字段可以通过XML配置、注解或JavaConfig来配置。
示例:通过XML配置Bean属性
<bean id="exampleBean" class="com.example.ExampleBean"> <property name="beanProperty" value="Some Value"/> </bean>
示例:通过注解配置Bean属性
@Component public class ExampleBean { @Value("${some.value}") private String beanProperty; }
Bean的依赖关系
Bean的依赖关系指的是一个Bean依赖于另一个Bean来完成其操作。例如,一个服务类(Service)可能依赖于一个数据访问对象(DAO)。
示例:通过XML配置Bean依赖
<bean id="myDao" class="com.example.MyDao"/> <bean id="myService" class="com.example.MyService"> <property name="myDao" ref="myDao"/> </bean>
示例:通过注解配置Bean依赖
@Service public class MyService { private final MyDao myDao; @Autowired public MyService(MyDao myDao) { this.myDao = myDao; } }
二、掌握Spring提供的属性配置和自动装配方式
属性配置
Spring提供了多种方式来配置Bean的属性,其中最常用的是@Value
注解。
使用@Value
注解
@Value
注解可以用来注入普通属性、系统属性、环境变量等。
@Component public class ExampleBean { @Value("${app.name:defaultAppName}") private String appName; }
自动装配
Spring的自动装配功能可以自动满足Bean之间的依赖,减少配置的工作量。最常用的自动装配注解是@Autowired
。
使用@Autowired
进行自动装配
Spring会在容器中查找匹配类型的Bean,并注入到被@Autowired
标注的字段、构造器或方法中。
@Service public class MyService { private final MyDao myDao; @Autowired public MyService(MyDao myDao) { this.myDao = myDao; // 自动装配 } }
高级自动装配
对于更复杂的自动装配场景,Spring提供了@Qualifier
和@Primary
注解来进一步控制自动装配的行为。
使用@Qualifier
指定具体的Bean
当有多个同类型的Bean可供选择时,@Qualifier
注解可以用来指定具体要装配的Bean。
@Autowired @Qualifier("specificDao") private MyDao myDao;
使用@Primary
指定首选的Bean
通过在Bean定义上使用@Primary
注解,可以指定当存在多个同类型Bean时,默认选择哪一个。
@Component @Primary public class PrimaryDao implements MyDao { // 实现细节 }
高级特性:BeanPostProcessor 和 FactoryBean
理解 BeanPostProcessor 和 FactoryBean 的作用和区别
在Spring框架中,BeanPostProcessor和FactoryBean是两个非常重要的接口,它们在Bean的生命周期管理和创建过程中扮演着关键角色。虽然它们的功能看似相近,但实际上各自的作用和应用场景大相径庭。
BeanPostProcessor:定制Bean的创建过程
BeanPostProcessor允许开发者插手Bean的初始化过程,在Bean的初始化前后执行一些自定义逻辑。
主要方法:
- postProcessBeforeInitialization(Object bean, String beanName): 在任何Bean初始化回调方法(如InitializingBean的afterPropertiesSet或自定义的init方法)之前调用。
- postProcessAfterInitialization(Object bean, String beanName): 在所有Bean初始化回调之后调用。
应用场景:
- 修改或包装Bean的实例,例如用代理包装一个Bean以提供额外的功能。
- 检查Bean属性的正确性或根据特定条件更改Bean的属性。
示例代码:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 在初始化之前执行的逻辑 return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // 在初始化之后执行的逻辑 return bean; } }
FactoryBean:专门用于生产对象的工厂Bean
与BeanPostProcessor不同,FactoryBean是用于生成其他Bean实例的特殊Bean。当配置的Bean实现了FactoryBean接口时,它将返回getObject()方法所返回的对象,而不是FactoryBean本身。
主要方法:
- T getObject(): 返回由FactoryBean创建的Bean实例。
- Class<?> getObjectType(): 返回FactoryBean创建的Bean类型。
- boolean isSingleton(): 表明由FactoryBean创建的Bean是否为单例。
应用场景:
- 创建复杂对象,当一个Bean的创建过程中涉及复杂逻辑时,可以使用
FactoryBean
封装这些逻辑。 - 返回的Bean实例可以是接口的代理,也可以是需要复杂初始化的对象。
示例代码:
import org.springframework.beans.factory.FactoryBean; public class MyFactoryBean implements FactoryBean<MyBean> { @Override public MyBean getObject() throws Exception { // 返回需要创建的Bean实例 return new MyBean(); } @Override public Class<?> getObjectType() { return MyBean.class; } @Override public boolean isSingleton() { // 控制该Bean是否为单例 return true; } }
BeanPostProcessor vs FactoryBean
虽然BeanPostProcessor和FactoryBean都可以影响Spring容器中Bean的创建,但它们的主要区别在于:
- BeanPostProcessor是用于修改或包装已经存在的Bean实例的。
- FactoryBean是用于创建新的Bean实例的。
Spring Boot 中的 Bean 管理和自动配置
探索Spring Boot:设计理念与自动配置深解
Spring Boot,作为现代Java开发中的一颗明星,以其“约定大于配置”的理念,极大地简化了Spring应用的开发、部署和运维。它不仅继承了Spring框架强大的依赖注入和面向切面编程的特性,还在此基础上提供了自动配置等功能,使得开发者可以更加专注于业务逻辑。本篇博客将带你深入理解Spring Boot的设计理念和主要特点,以及它在Bean管理和自动配置方面的实现原理。
Spring Boot的设计理念和主要特点
设计理念
Spring Boot遵循“约定大于配置”的原则,旨在减少项目搭建的复杂性和开发时的配置要求。它通过合理的默认配置,帮助开发者快速启动和开发Spring应用程序。
主要特点
- 自动配置:自动配置Spring和第三方库,尽可能地减少配置文件的使用。
- 独立运行:生成的应用程序可以直接运行,不需要外部的Servlet容器。
- 运维友好:提供了丰富的监控和管理功能,支持健康检查、应用信息查看等。
- 无代码生成和XML配置:不需要生成代码或进行XML配置,通过注解和自动装配完成配置。
深入掌握Spring Boot在Bean管理和自动配置方面的实现原理
Bean管理
Spring Boot利用Spring框架的依赖注入(DI)特性来管理Bean。开发者可以通过注解如@Component、@Service、@Repository等来声明Bean,并通过@Autowired或构造器注入依赖。
示例:定义和注入Bean
@Service public class MyService { // 业务逻辑 } @RestController public class MyController { private final MyService myService; @Autowired public MyController(MyService myService) { this.myService = myService; // 自动装配 } }
自动配置原理
Spring Boot自动配置的魔法背后是@EnableAutoConfiguration注解,这个注解通过@Import引入了AutoConfigurationImportSelector类,该类负责读取META-INF/spring.factories文件中的配置,根据条件选择性地应用配置。
示例:自动配置的简化示例
假设我们有一个自动配置类MyAutoConfiguration
,当classpath中存在某个特定类时,这个配置类就会被应用:
@Configuration @ConditionalOnClass(SomeClass.class) public class MyAutoConfiguration { @Bean public SomeBean someBean() { return new SomeBean(); } }
在resources/META-INF/spring.factories
文件中,我们声明这个自动配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.MyAutoConfiguration
当Spring Boot应用启动时,如果classpath中存在SomeClass
,那么SomeBean
就会被自动配置。