Spring Bean的生命周期

Spring Bean的生命周期也是高频的面试题目,下面我就写写Spring 中一个Bean从初始化到销毁的生命周期。

先上图

Bean的生命周期

上面的图可以分成下面的几步:

1.实例化Bean

2.属性注入

3.如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String) 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值

4.如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory, setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它 Bean, 只需在 Spring 配置文件中配置一个普通的 Bean 就可以)

5.如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext)方法,传入 Spring 上下文

6.如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用 postProcessBeforeInitialization(Object obj, String s)方法(前置处理)

7.如果实现了InitializingBean接口,就会调用afterPropertiesSet()方法

8.如果Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法(初始化方法)

9.如果第5点成立,那么就会调用postProcessAfterInitialization(Object bean,String beanName)方法 (后置处理)

10.当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用那个其实现的 destroy()方法;如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的 销毁方法

下面是上面步骤的证明:

这里先不在配置文件中配置实现了BeanPostProcessor的接口的类,因为这个类是起增强(个人觉得)效果的,下面再配置这个类。

生命过程:

运行结果:
运行结果

Bean


 1. public class LoginService implements BeanNameAware,
    InitializingBean, DisposableBean, BeanFactoryAware,
    ApplicationContextAware {
    
        private String name;
    
        public LoginService(String name) {
            this.name = name;
        }
    
        public LoginService() {
            System.out.println("实例化LoginService对象");
        }
    
        public void setName(String name) {
            System.out.println("设置了name的属性,name =" + name);
            this.name = name;
        }
    
        @Override
        public void setBeanName(String s) {
            System.out.println("调用BeanNameAware的setBeanName方法设置Bean的名称为:" + s);
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("调用InitializingBean的afterPropertiesSet方法");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("调用DisposableBean的destroy方法");
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("调用BeanFactoryAware的setBeanFactory方法");
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("调用ApplicationContextAware的setApplicationContext方法");
        }
    
        public  void init(){
            System.out.println("Bean被实例化后调用的init()方法");
        }
    
        public void destory(){
            System.out.println("Bean被销毁了");
        }
    
        public void login(){
            System.out.println("自定义方法login()开始登陆");
        }
    
    
    
            public void mydestory(){
            System.out.println("Bean被销毁了");
        } }

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="service.LoginService" init-method="init" id="loginService" >
        <property name="name" value="小明"/>
    </bean>
</beans>

启动类

启动类

上面是没有加入BeanPostProcessor这个类的运行结果,下面就再看看加入这个类的运行结果,在这之前,先看看这个类有什么作用。

先看看官方文档怎么说的:

public interface BeanPostProcessor
Factory hook that allows for custom modification of new bean instances — for example, checking for marker interfaces or wrapping beans with proxies.
Typically, post-processors that populate beans via marker interfaces or the like will implement postProcessBeforeInitialization(java.lang.Object, java.lang.String), while post-processors that wrap beans with proxies will normally implement postProcessAfterInitialization(java.lang.Object, java.lang.String).

翻译成中文:

允许自定义修改新bean实例的工厂钩子——例如,检查标记接口或用代理包装bean。
通常,通过标记接口或类似的方式填充bean的后处理器将实现postprocessbeforeinitialize (java.lang)。而使用代理包装bean的后处理器通常会实现postprocessafterinitialize (java.lang. string)。对象,以)。

这个类就提供了两个方法:postProcessBeforenitialization(Object bean, String beanName)和postProcessAfterInitialization(Object bean, String beanName);两个参数分别传递 实例化的bean(Object bean)和bean的名称(String beanName),在这两个方法中可以修改类的属性。

下面先看一下Bean的生命周期:

运行结果
在这里插入图片描述

BeanPostProcessor实现类

public class TestBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      
        System.out.println("调用了TestBeanPostProcessor的postProcessBeforeInitialization方法");
        return null;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   
        System.out.println("调用了TestBeanPostProcessor的postProcessAfterInitialization方法");
  
        return null;
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="service.LoginService" init-method="init" id="loginService" >
        <property name="name" value="小明"/>
    </bean>
    <bean class="service.TestBeanPostProcessor"></bean>
</beans>

从上面的结果可以看到跟Bean的生命周期跟流程图一样。

最后来看看BeanPostProcessor中两个方法的作用,其实这两个方法的主要作用是修改bean里面的内容,下面来看看它们是怎么修改bean里面的内容。

上面我们说过那两个参数Object 和BeanName传递的内容了,它们分别是传递Bean的实例化对象和Bean的名称。

我们首先在配置文件中设置了Name的属性

在这里插入图片描述
启动
在这里插入图片描述
然后在postProcessBeforeInitialzation方法中再设置name的属性, 把name的值设置为 “postProcessBeforeInitialization方法里面设置的name”

在这里插入图片描述

然后我们在postProcessAfterInitialization方法读取name的属性,然后在把name的值设置为 “postProcessAfterInitialization里面设置的name”

在这里插入图片描述

读取的结果

在这里插入图片描述

在上面我们可以看到读取name的值 是我们在postProcessBeforeInitialization中设置的值了,说明在这个方法中我们是可以修改到Bean里面的内容,但是在postProcessAfterInitialization方法中我们又修改了name的值,这时候我们在容器中的Bean,它的name里面的值是什么呢?

在容器中获取

在这里插入图片描述

结果

在这里插入图片描述
在上面我们可以看到name的值为在postProcessInitialization方法中修改的值,可见这两个方法都能修改Bean的内容,但是修改的顺序不同。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值