Spring Bean 生命周期

发布于 2025-03-04 22:28:46 字数 8635 浏览 6 评论 0

在 Spring 中,那些组成应用程序的主体及由 Spring IoC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IoC 容器初始化、装配及管理的对象,除此之外,bean 就与应用程序中的其他对象没有什么区别了。而 bean 的定义以及 bean 相互间的依赖关系将通过配置元数据来描述。

Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。

首先看下生命周期图:

bean 的五种作用域作

五种作用域中,request、session 和 global session 三种作用域仅在基于 web 的应用中使用(不必关心你所采用的是什么 web 应用框架),只能用在基于 web 的 Spring ApplicationContext 环境。

Singleton 作用域

  • 当一个 bean 的作用域为 Singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton 作用域是 Spring 中的缺省作用域。
    要在 XML 中将 bean 定义成 singleton,可以这样配置:
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

Prototype 作用域

  • 当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例。Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取 bean 的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bea
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 

request 作用域

  • 当一个 bean 的作用域为 Request,表示在一次 HTTP 请求中,一个 bean 定义对应一个实例;即每个 HTTP 请求都会有各自的 bean 实例,它们依据某个 bean 定义创建而成。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。考虑下面 bean 定义:
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
  • 针对每次 HTTP 请求,Spring 容器会根据 loginAction bean 的定义创建一个全新的 LoginAction bean 实例,且该 loginAction bean 实例仅在当前 HTTP request 内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据 loginAction bean 定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request 作用域的 bean 实例将被销毁。

session 作用域

  • 当一个 bean 的作用域为 Session,表示在一个 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。考虑下面 bean 定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

global session 作用域

  • 当一个 bean 的作用域为 Global Session,表示在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。典型情况下,仅在使用 portlet context 的时候有效。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。考虑下面 bean 定义:
<bean id="user" class="com.foo.Preferences "scope="globalSession"/>
  • global session 作用域类似于标准的 HTTP Session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portlet 所共享。在 global session 作用域中定义的 bean 被限定于全局 portlet Session 的生命周期范围内。

Bean 实例生命周期的执行过程如下:

  1. Spring 对 bean 进行实例化,默认 bean 是单例;
  2. Spring 对 bean 进行依赖注入;
  3. 如果 bean 实现了 BeanNameAware 接口,spring 将 bean 的 id 传给 setBeanName() 方法;
  4. 如果 bean 实现了 BeanFactoryAware 接口,spring 将调用 setBeanFactory 方法,将 BeanFactory 实例传进来;
  5. 如果 bean 实现了 ApplicationContextAware 接口,它的 setApplicationContext() 方法将被调用,将应用上下文的引用传入到 bean 中;
  6. 如果 bean 实现了 BeanPostProcessor 接口,它的 postProcessBeforeInitialization 方法将被调用;
  7. 如果 bean 实现了 InitializingBean 接口,spring 将调用它的 afterPropertiesSet 接口方法,类似的如果 bean 使用了 init-method 属性声明了初始化方法,该方法也会被调用;
  8. 如果 bean 实现了 BeanPostProcessor 接口,它的 postProcessAfterInitialization 接口方法将被调用;
  9. 此时 bean 已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;
  10. 若 bean 实现了 DisposableBean 接口,spring 将调用它的 distroy() 接口方法。同样的,如果 bean 使用了 destroy-method 属性声明了销毁方法,则该方法被调用;

springBean 自定义初始化和销毁方法

springBoot 方式

public class SpringLifeCycle {
private final static Logger LOGGER = LoggerFactory.getLogger(LifeCycleConfig.class);
public void start(){
  LOGGER.info("bean 初始化 start");
}
public void destroy(){
  LOGGER.info("bean 销毁 destroy");
}
}

@Configuration
public class LifeCycleConfig {
@Bean(initMethod = "start", destroyMethod = "destroy")
public SpringLifeCycle create(){
  SpringLifeCycle springLifeCycle = new SpringLifeCycle() ;

  return springLifeCycle ;
}

}

@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {

@Test
public void contextLoads() {
  System.out.println("dsadsasdasd");
  SpringLifeCycle s=new SpringLifeCycle();
}

}

传统 xml 配置方式

<bean id="person1" destroy-method="myDestroy" 
    init-method="myInit" class="com.test.spring.life.Person">
  <property name="name">
    <value>jack</value>
  </property>
</bean>
<!-- 配置自定义的后置处理器 -->
<bean id="postProcessor" class="com.pingan.spring.life.MyBeanPostProcessor" />
public class Person implements BeanNameAware, BeanFactoryAware,
  ApplicationContextAware, InitializingBean, DisposableBean {

private String name;

public Person() {
  System.out.println("PersonService 类构造方法");
}


public String getName() {
  return name;
}
public void setName(String name) {
  this.name = name;
  System.out.println("set 方法被调用");
}

//自定义的初始化函数
public void myInit() {
  System.out.println("myInit 被调用");
}

//自定义的销毁方法
public void myDestroy() {
  System.out.println("myDestroy 被调用");
}

public void destroy() throws Exception {
  // TODO Auto-generated method stub
  System.out.println("destory 被调用");
}

public void afterPropertiesSet() throws Exception {
  // TODO Auto-generated method stub
  System.out.println("afterPropertiesSet 被调用");
}

public void setApplicationContext(ApplicationContext applicationContext)
    throws BeansException {
  // TODO Auto-generated method stub
  System.out.println("setApplicationContext 被调用");
}

public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  // TODO Auto-generated method stub
    System.out.println("setBeanFactory 被调用,beanFactory");
}

public void setBeanName(String beanName) {
  // TODO Auto-generated method stub
  System.out.println("setBeanName 被调用,beanName:" + beanName);
}

public String toString() {
  return "name is :" + name;
}
public class MyBeanPostProcessor implements BeanPostProcessor {

public Object postProcessBeforeInitialization(Object bean,
    String beanName) throws BeansException {
  // TODO Auto-generated method stub
  
  System.out.println("postProcessBeforeInitialization 被调用");
  return bean;
}

public Object postProcessAfterInitialization(Object bean,
    String beanName) throws BeansException {
  // TODO Auto-generated method stub
  System.out.println("postProcessAfterInitialization 被调用");
  return bean;
}

}

测试类

public class MyBeanPostProcessor implements BeanPostProcessor {

public Object postProcessBeforeInitialization(Object bean,
    String beanName) throws BeansException {
  // TODO Auto-generated method stub
  
  System.out.println("postProcessBeforeInitialization 被调用");
  return bean;
}

public Object postProcessAfterInitialization(Object bean,
    String beanName) throws BeansException {
  // TODO Auto-generated method stub
  System.out.println("postProcessAfterInitialization 被调用");
  return bean;
}

}

public static void main(String[] args) {
  // TODO Auto-generated method stub

  System.out.println("开始初始化容器");
  ApplicationContext ac = new ClassPathXmlApplicationContext("com/test/spring/life/applicationContext.xml");
  
  System.out.println("xml 加载完毕");
  Person person1 = (Person) ac.getBean("person1");
  System.out.println(person1);    
  System.out.println("关闭容器");
  ((ClassPathXmlApplicationContext)ac).close();
  
}

使用前面定义好的 Person 类和 MyBeanPostProcessor 类,以及 ApplicationContext.xml 文件,main 函数实现如下:

public static void main(String[] args) {
  // TODO Auto-generated method stub
  System.out.println("开始初始化容器");  
  ConfigurableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("com/pingan/spring/life/applicationContext.xml"));
  System.out.println("xml 加载完毕");    
  //beanFactory 需要手动注册 beanPostProcessor 类的方法
  bf.addBeanPostProcessor(new MyBeanPostProcessor());
  Person person1 = (Person) bf.getBean("person1");
    System.out.println(person1);
  System.out.println("关闭容器");
  bf.destroySingletons();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
25 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文