前言
Spring框架是一个非常流行的Java企业级应用程序框架,已经成为许多生产环境中的首选技术。它提供了一种便捷的方法来帮助开发人员构建可扩展和模块化的企业级应用程序。在Spring框架中,Bean生命周期是非常重要的一部分,它负责Bean的创建和销毁。
一个完整的Spring的Bean的生命周期
Spring框架中Bean的完整生命周期包括:
- 实例化Bean
- 设置对象属性
- 对Bean执行用户定义的初始化方法
- Bean可用
- 关闭容器
实例化Bean
在 Spring 中,实例化 Bean 主要有两种方式:使用构造函数实例化和使用静态工厂方法实例化。
构造函数实例化是使用类的构造函数创建 Bean 对象的方式。在 Spring 配置文件中,可以通过 元素的 constructor-arg 子元素来指定 Bean 的构造函数参数。
静态工厂方法实例化是指在 BeanFactory 创建 Bean 实例时,调用静态工厂方法创建 Bean 对象。在 Spring 配置文件中,可以通过 元素的 class 属性和 factory-method 属性来指定 Bean 工厂类和工厂方法。
需要注意的是,在 Spring 中,Bean 实例化后并不直接进入使用状态,而是存放在 BeanFactory 中,等待被其他 Bean 使用。如果没有配置 Bean 的作用域为 singleton,则每次使用 Bean 时都会创建一个新的 Bean 实例。
在Bean实例化的时候,有几个比较重要的接口,我们可以看下。
1. BeanFactoryPostProcessor
BeanFactoryPostProcessor它能够让开发人员在Bean工厂创建Bean之前对其进行配置或修改,同时还能在Bean实例化之前进行一些定制化操作。通过BeanFactoryPostProcessor接口,开发人员可以访问到Spring容器内的BeanFactory,从而改变Bean的配置信息,例如将某个Bean的scope从singleton改变为prototype。
BeanFactoryPostProcessor接口包括一个方法postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory ),它接收一个ConfigurableListableBeanFactory对象作为参数,这个对象可以被用来修改BeanFactory的配置。实现自定义BeanFactoryPostProcessor非常简单:只需要创建一个实现该接口的类,并在Spring配置文件中声明Bean即可。
2. BeanPostProcessor
当我们在创建Bean的时候,Spring框架会按照Bean的生命周期方法先后顺序执行相应的方法。其中BeanPostProcessor接口定义了两个方法,beforeInitialization和afterInitialization,用于在Bean初始化前和Bean初始化后进行处理。
BeanPostProcessor的主要作用是对Bean的实例进行后置处理。在Bean实例创建完成之后,BeanPostProcessor实例会对Bean进行一些额外的处理,或者说是修饰。例如,开发人员可以借助于BeanPostProcessor来实现一些非侵入式的集中式日志记录或者为Bean装配前初始化某些属性值,以及为Bean设置代理等。
设置对象属性
设置对象属性是Spring Bean生命周期中的一个阶段。在这个阶段,Spring框架会根据Bean的配置信息为对象设置属性并将其装配到应用程序中。
具体实现方法是在Bean的配置信息中添加属性元素,用于配置对象的属性值。例如:
<bean id="exampleBean" class="com.example.Example">
<property name="name" value="John Doe" />
<property name="age" value="30" />
</bean>
在上面的例子中,我们定义了一个名为exampleBean的Bean,它的类是com.example.Example。我们使用元素设置了对象的两个属性:name和age。可以看到,我们通过name属性指定了要设置的属性名,通过value属性指定要设置的属性值。Spring框架将使用反射机制调用对象的setter方法,并将属性值设置为参数。
另外,在使用注解的方式配置Bean时,也可以使用@Autowired注解或者@Resource注解为对象的属性进行自动装配。这些注解可以根据Type或Name自动查找适配的Bean进行装配,从而减少了手动配置Bean属性的工作。例如:
@Component
public class ExampleComponent {
@Autowired
private ExampleBean exampleBean;
public void doSomething() {
// 使用exampleBean对象执行一些操作
}
}
@Component
public class ExampleBean {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
在上面的例子中,我们定义了一个使用@Autowired注解进行注入的ExampleComponent 组件,并将其属性exampleBean注入了一个ExampleBean对象。当Spring框架启动时,它会自动为ExampleComponent组件实例化对象,并调用setter方法将exampleBean对象注入到ExampleComponent中。
对Bean执行用户定义的初始化方法
对Bean执行用户定义的初始化方法在Spring框架中是通过Bean的生命周期回调方法来实现的。具体步骤如下:
1. 实现InitializingBean
InitializingBean是Spring框架中一个非常重要的接口之一,定义了Bean初始化后要执行的操作。在BeanFactory完成对Bean实例的配置和添加Bean实例的前置和后置处理工作之后,Spring容器将调用InitializingBean接口的afterPropertiesSet方法进行Bean的初始化执行操作。
在Spring容器中,实现InitializingBean接口的类变得非常重要,它允许开发人员控制Bean的完整生命周期。开发人员可以借助于afterPropertiesSet方法,为Bean初始化一些数据或者修饰/验证已经设置的某些依赖。
在Bean类中实现InitializingBean接口,该接口中定义了一个afterPropertiesSet()方法,该方法会在Bean初始化完成之后被调用。
public class MyBean implements InitializingBean {
// ...
@Override
public void afterPropertiesSet() throws Exception {
// 在这里编写Bean初始化的逻辑
// ...
}
// ...
}
2. 使用@PostConstruct注解
还可以使用@PostConstruct注解,在Bean初始化完成之后执行指定的方法,例如:
public class MyBean {
// ...
@PostConstruct
public void init() {
// 在这里编写Bean初始化的逻辑
// ...
}
// ...
}
3. 指定init方法
也可以在XML配置文件中指定Bean初始化时调用的方法,例如:
<bean id="myBean" class="com.example.MyBean" init-method="init"/>
其中,init-method属性指定了Bean初始化时要调用的方法名。
以上是三种常用的对Bean执行用户定义的初始化方法的实现方式,您可以根据具体情况选择其中的一种方式。
Bean可用
简单来说,在Spring生命周期中,Bean可用是在BeanFactory启动阶段的某个时刻被触发的,表示这个Bean已经完成了所有的初始化工作,可以被其他Bean调用和使用。在这个状态下,Bean已经处于正常运行状态,可以对外提供服务或者处理业务逻辑。
这里提供一个简单的Spring生命周期Bean可用的示例代码。首先,我们定义一个名为BeanLifeCycleDemo
的类,并指定初始化和销毁方法。代码如下:
public class BeanLifeCycleDemo {
private String message;
public void init() {
System.out.println("Bean is being initialized.");
this.message = "Hello, world!";
}
public void destroy() {
System.out.println("Bean is being destroyed.");
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
}
接下来,我们需要在Spring配置文件中声明这个类的Bean,并指定它的初始化和销毁方法。配置文件为beans.xml
,代码如下:
<bean id="beanLifeCycleDemo" class="com.example.BeanLifeCycleDemo"
init-method="init" destroy-method="destroy">
<property name="message" value="Hello, world!"/>
</bean>
在这个示例中,我们使用了Spring的依赖注入功能,将属性
message
设置为Hello, world!
。同时,我们指定了Bean的初始化方法为init()
,和销毁方法为destroy()
。
最后,我们创建一个测试类AppTest
,并在其中测试输出Bean的信息。代码如下:
public class AppTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
BeanLifeCycleDemo bean = context.getBean("beanLifeCycleDemo", BeanLifeCycleDemo.class);
System.out.println(bean.getMessage());
context.close();
}
}
在这个测试类中,我们使用
ClassPathXmlApplicationContext
类创建了Spring容器,并通过context.getBean()
方法获取了Bean实例。然后,我们输出了Bean的信息,即Hello, world!
,并调用了context.close()
方法,销毁了Bean。在控制台输出中,我们可以看到初始化方法“Bean is being initialized.”和销毁方法“Bean is being destroyed.”的信息。
通过以上示例,我们可以看到,在Spring生命周期中,Bean可用是在Bean初始化完成后被触发的。在这个状态下,我们可以对Bean进行操作,包括调用它的方法、获取它的属性等。
关闭容器
在 Spring 框架中,Bean 生命周期的最后一个阶段是关闭容器,即当应用程序完成运行时,应调用 ApplicationContext 的 close() 方法,以便释放所有资源和 Bean 所占用的内存。当 ApplicationContext 关闭时,它会通知 Bean,以便它们可以对关闭操作作出响应。
以下是关闭容器时 Bean 生命周期涉及的步骤:
- 当 BeanFactory 关闭时,将调用所有 DisposableBean 实例的 destroy() 方法。
DisposableBean是Spring框架中一个很关键的接口。它定义了Bean在销毁时要执行的操作。在一个Bean被容器实例化之后,在容器销毁Bean之前,会调用Bean实现的这个接口。最常见的操作包括关闭数据库连接或停止根据消息队列执行的任务。如果有需要在Bean销毁之前释放某些资源,那么实现DisposableBean是很重要的。
-
如果 Bean 实现了 DisposableBean 接口,则调用 destroy() 方法。这个方法允许 Bean 清理任何在应用程序运行时已经初始化或记录的资源。
-
调用在 Bean 定义中定义的任何自定义销毁方法。自定义销毁方法可以通过指定 destroy-method 属性来定义。例如:
<bean id="myBean" class="com.example.MyBean" destroy-method="cleanup"/>
这里的 cleanup() 方法将在关闭容器时被调用。
-
关闭内部 bean 容器。
如果 bean 是 ApplicationContext 的子容器,则首先关闭子容器中的 bean。然后关闭 ApplicationContext 自身,以确保所有 bean 处于已销毁状态。
需要注意的是,在应用程序关闭时,所有的资源,如数据库连接、文件句柄等,必须被有效地释放。因此,实现 destroy() 和自定义销毁方法是非常重要的。通过这些方法,可以确保 bean 释放所有的资源,并在关闭应用程序时正确地退出。
除了使用销毁方法之外,还可以使用注解来标注Bean的初始化和销毁方法。@PostConstruct和@PreDestroy是两个Spring框架中内置的注解,这些注解可以使用在任何方法上,只要符合Bean的规范即可。
@PostConstruct注解在Bean的初始化之后调用,@PreDestroy注解则在Bean被销毁之前调用。在使用注解的时候,只需要定义需要执行的方法,就可以同时实现Bean初始化和销毁的效果。
结论
Spring的Bean生命周期可以分为两个阶段:BeanFactory准备和BeanFactory启动,其中Bean创建、初始化、销毁等过程都在这个时间段内完成。在BeanFactory准备阶段,Spring容器对BeanFactory进行了初始化,包括加载配置文件、实例化Bean工厂等。在该阶段,调用了Bean Factory Post Processor(BFPP)和Bean Post Processor(BPP)等接口,对FactoryBean和普通Bean进行预处理。在BeanFactory启动阶段,Spring容器启动后会实例化所有的Bean,并根据定义的属性、依赖等设置对Bean进行初始化。在这个过程中,调用了Bean的构造函数和初始化方法,对Bean进行了依赖注入等操作,同时也触发了Bean可以使用的状态。在容器关闭时,Spring会调用Bean的销毁方法以进行一些清理工作。