SpringBean生命周期
Spring Bean 简介
如何注册一个 Spring Bean?
通过 BeanDefinition 和外部单体对象来注册
BeanDefinition
什么是 BeanDefinition
BeanDefinition
是 Spring Framework 中定义 Bean 的配置元信息接口,包含:
Bean 类名
Bean 行为配置元素,如:作用域、自动绑定的模式、生命周期回调等
其他 Bean 引用
配置设置,如 Bean 属性(Properties)
l#beandefinition-元信息)BeanDefinition 元信息
BeanDefinition
元信息如下:
BeanDefinition 构建
BeanDefinition 构建方式:
通过
BeanDefinitionBuilder
通过
AbstractBeanDefinition
以及派生类
// 1.通过 BeanDefinitionBuilder 构建
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
// 通过属性设置
beanDefinitionBuilder
.addPropertyValue("id", 1)
.addPropertyValue("name", "小马哥");
// 获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// BeanDefinition 并非 Bean 终态,可以自定义修改
// 2. 通过 AbstractBeanDefinition 以及派生类
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
// 设置 Bean 类型
genericBeanDefinition.setBeanClass(User.class);
// 通过 MutablePropertyValues 批量操作属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue("id", 1);
// propertyValues.addPropertyValue("name", "小马哥");
propertyValues
.add("id", 1)
.add("name", "小马哥");
// 通过 set MutablePropertyValues 批量操作属性
genericBeanDefinition.setPropertyValues(propertyValues);
命名 Spring Bean
Spring Bean 命名规则
每个 Bean 拥有一个或多个标识符(identifiers),这些标识符在 Bean 所在的容器必须是唯一的。通常,一个 Bean 仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来扩充。
在基于 XML 的配置元信息中,开发人员可用 id 或者 name 属性来规定 Bean 的标识符。通常 Bean 的标识符由字母组成,允许出现特殊字符。如果要想引入 Bean 的别名的话,可在 name 属性使用半角逗号(“,”)或分号(“;”) 来间隔。
Bean 的 id 或 name 属性并非必须制定,如果留空的话,容器会为 Bean 自动生成一个唯一的名称。Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合 Java 的命名约定。
Spring Bean 命名生成器
Spring 提供了两种 Spring Bean 命名生成器:
DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现。
AnnotationBeanNameGenerator:基于注解扫描的 BeanNameGenerator 实现。
public interface BeanNameGenerator {
String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry);
}
Spring Bean 别名
可能存在这样的场景,不同系统中对于同一 bean 的命名方式不一样。 为了适配,Spring 支持 <alias>
为 bean 添加别名的功能。
<bean id="user" class="io.github.dunwu.spring.core.domain.User"
p:name="张三" p:age="18">
</bean>
<alias name="sysUser" alias="superUser" />
Bean 别名(Alias)的作用:
复用现有的 BeanDefinition
更具有场景化的命名方法,比如:
<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
Bean 生命周期流程
Spring 对 Bean 进行实例化(相当于 new XXX())
Spring 将值和引用注入进 Bean 对应的属性中
如果 Bean 实现了
BeanNameAware
接口,Spring 将 Bean 的 ID 传递给setBeanName
方法作用是通过 Bean 的引用来获得 Bean ID,一般业务中是很少有用到 Bean 的 ID 的
如果 Bean 实现了
BeanFactoryAware
接口,Spring 将调用setBeanDactory
方法,并把BeanFactory
容器实例作为参数传入。作用是获取 Spring 容器,如 Bean 通过 Spring 容器发布事件等
如果 Bean 实现了
ApplicationContextAware
接口,Spring 容器将调用setApplicationContext
方法,把应用上下文作为参数传入作用与
BeanFactory
类似都是为了获取 Spring 容器,不同的是 Spring 容器在调用setApplicationContext
方法时会把它自己作为setApplicationContext
的参数传入,而 Spring 容器在调用setBeanFactory
前需要使用者自己指定(注入)setBeanFactory
里的参数BeanFactory
如果 Bean 实现了
BeanPostProcess
接口,Spring 将调用postProcessBeforeInitialization
方法作用是在 Bean 实例创建成功后对其进行增强处理,如对 Bean 进行修改,增加某个功能
如果 Bean 实现了
InitializingBean
接口,Spring 将调用afterPropertiesSet
方法,作用与在配置文件中对 Bean 使用init-method
声明初始化的作用一样,都是在 Bean 的全部属性设置成功后执行的初始化方法。如果 Bean 实现了
BeanPostProcess
接口,Spring 将调用postProcessAfterInitialization
方法postProcessBeforeInitialization
是在 Bean 初始化前执行的,而postProcessAfterInitialization
是在 Bean 初始化后执行的
经过以上的工作后,Bean 将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
如果 Bean 实现了
DispostbleBean
接口,Spring 将调用它的destory
方法,作用与在配置文件中对 Bean 使用destory-method
属性的作用一样,都是在 Bean 实例销毁前执行的方法。
Spring Bean 注册
注册 Spring Bean 实际上是将 BeanDefinition
注册到 IoC 容器中。
XML 配置元信息
Spring 的传统配置方式。在 <bean>
标签中配置元数据内容。
缺点是当 JavaBean 过多时,产生的配置文件足以让你眼花缭乱。
注解配置元信息
使用 @Bean
、@Component
、@Import
注解注册 Spring Bean。
Java API 配置元信息
命名方式:
BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
非命名方式:
BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,Be
anDefinitionRegistry)
配置类方式:
AnnotatedBeanDefinitionReader#register(Class...)
[示例]
@Import(AnnotationComponentScan.MyConfiguration.class)
public class AnnotationComponentScan {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// 1.注册配置类
ctx.register(AnnotationComponentScan.class);
// 2.通过 Java API 注册
registerBeanDefinition(ctx, "zhaoliu", User.class);
// 启动应用上下文
ctx.refresh();
User wangwu = (User) ctx.getBean("wangwu");
System.out.println("wangwu info: " + wangwu);
System.out.println("All beans of User: " + ctx.getBeansOfType(User.class));
//显示关闭 ApplicationContext
ctx.close();
}
public static void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName, Class<?> beanClass) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
builder.addPropertyValue("name", "赵六");
builder.addPropertyValue("age", 31);
// 注册 BeanDefinition
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
@Configuration
public static class MyConfiguration {
// 注解方式配置元信息
@Bean(name = { "user", "wangwu" })
public User user() {
return new User("王五", 21);
}
}
}
Spring Bean 实例化
Spring Bean 实例化方式:
常规方式
通过构造器(配置元信息:XML、Java 注解和 Java API)
通过静态工厂方法(配置元信息:XML、Java 注解和 Java API)
通过 Bean 工厂方法(配置元信息:XML、Java 注解和 Java API)
通过
FactoryBean
(配置元信息:XML、Java 注解和 Java API)
特殊方式
通过
ServiceLoaderFactoryBean
(配置元信息:XML、Java 注解和 Java API )通过
AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
通过
BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
Spring Bean 初始化和销毁
Spring Bean 初始化和销毁的方式有以下几种:
使用
@PostConstruct
和@PreDestroy
注解分别指定相应的初始化方法和销毁方法。实现
InitializingBean
接口的afterPropertiesSet()
方法来编写初始化方法;实现DisposableBean
接口的destroy()
方法来编写销毁方法。自定义初始化方法
XML 配置:
<bean init-method="init" destroy="destroy" ... />
Java 注解:
@Bean(initMethod = "init", destroyMethod = "destroy")
Java API:
AbstractBeanDefinition#setInitMethodName(String)
和AbstractBeanDefinition#setDestroyMethodName(String)
分别定义初始化和销毁方法
注意:如果同时存在,执行顺序会按照序列执行。
@Bean
的 initMethod 和 destroyMethod
(1)定义 Bean 实例
public class Pojo {
public Pojo() {
System.out.println("[Pojo 构造方法]");
}
public void init() {
System.out.println("[Pojo 初始化方法]");
}
public void destroy() {
System.out.println("[Pojo 销毁方法]");
}
}
(2)使用 @Bean
在配置类中注册 Bean
@Configuration
public class AnnotationBeanDemo {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Pojo pojo() {
return new Pojo();
}
}
说明:
@Bean
注解的initMethod
和destroyMethod
属性分别用于指定 Bean 对应的初始化方法和销毁方法。
(3)测试:
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationBeanDemo.class);
System.out.println("AnnotationBeanDemo 示例结束");
context.close();
}
输出
[Pojo 构造方法]
[Pojo 初始化方法]
AnnotationBeanDemo 示例结束
[Pojo 销毁方法]
InitializingBean
和 DisposableBean
InitializingBean
接口包含一个afterPropertiesSet
方法,可以通过实现该接口,然后在这个方法中编写初始化逻辑。DisposableBean
接口包含一个destory
方法,可以通过实现该接口,然后在这个方法中编写销毁逻辑。
(1)定义 Bean 实例
public static class Pojo2 implements InitializingBean, DisposableBean {
public Pojo2() {
System.out.println("[Pojo2 构造方法]");
}
@Override
public void afterPropertiesSet() {
System.out.println("[Pojo2 初始化方法]");
}
@Override
public void destroy() {
System.out.println("[Pojo2 销毁方法]");
}
}
(2)使用 @Bean
在配置类中注册 Bean
@Configuration
public class AnnotationBeanDemo {
@Bean
public Pojo2 pojo2() {
return new Pojo2();
}
}
(3)测试:
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationBeanDemo.class);
System.out.println("AnnotationBeanDemo 示例结束");
context.close();
}
输出
[Pojo2 构造方法]
[Pojo2 初始化方法]
AnnotationBeanDemo 示例结束
[Pojo2 销毁方法]
@PostConstruct
和 @PreDestroy
可以使用 @PostConstruct
和 @PreDestroy
注解修饰方法来指定相应的初始化和销毁方法。
BeanPostProcessor
Spring 提供了一个 BeanPostProcessor
接口,提供了两个方法 postProcessBeforeInitialization
和 postProcessAfterInitialization
。其中postProcessBeforeInitialization
在组件的初始化方法调用之前执行,postProcessAfterInitialization
在组件的初始化方法调用之后执行。它们都包含两个入参:
bean:当前组件对象;
beanName:当前组件在容器中的名称。
(1)定义 Pojo,如上面的例子
(2)定义 BeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("[BeanPostProcessor] construct");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[BeanPostProcessor] postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("[BeanPostProcessor] postProcessAfterInitialization");
return bean;
}
}
(3)使用 @Bean
在配置类中注册 Bean
@Bean
public Pojo pojo() {
return new Pojo();
}
@Bean
public MyBeanPostProcessor myBeanPostProcessor() {
return new MyBeanPostProcessor();
}
(3)测试:
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyBeanPostProcessorDemo.class);
System.out.println("BeanPostProcessorDemo 示例结束");
context.close();
}
输出
[BeanPostProcessor] construct
[Pojo 构造方法]
[BeanPostProcessor] postProcessBeforeInitialization
[Pojo 初始化方法]
[BeanPostProcessor] postProcessAfterInitialization
BeanPostProcessorDemo 示例结束
[Pojo 销毁方法]
Spring Bean 垃圾回收
Spring Bean 垃圾回收步骤:
关闭 Spring 容器(应用上下文)
执行 GC
Spring Bean 覆盖的 finalize() 方法被回调
参考资料
- 感谢你赐予我前进的力量