Spring6 当中 Bean 的生命周期的详细解析:有五步,有七步,有十步

1. Spring6 当中 Bean 的生命周期的详细解析:有五步,有七步,有十步

@


每博一文案

“这个世界本来就是这样的,会认识形形色色的人,会遇到无法理解的恶意,
会感到失望,但是只要过去了,你就会发现,那些带着偏见自说自话的言论,
还有那些不能理解的恶意,都是在提醒我们不要成为那样的人。
或许会焦虑,会不知所措,生活也不太如意,会感到绝望。但我想说:前路漫漫,需自身强大。”

世界就是如此复杂,生活也从不是尽如人意,但我还是希望你,
即使见过那些肮脏与不堪,也依然能保有一颗温良的心。深渊可以凝视,但不要驻足。

只要心存光明,世界就不黑暗。

1.1 什么是 Bean 的生命周期

Spring 其实就是一个管理 Bean 对象的工厂。它负责对象的创建,对象的销毁等。

所谓的生命周期:简单的来说:就是一个对象从创建开始到最终销毁的整个过程。

  • 什么时候创建Bean 对象 ?
  • 创建 Bean 对象的前后会调用什么方法?
  • Bean 对象什么时候销毁?
  • Bean 对象的在销毁前后会调用生命方法?

那么我们为什么要知道 Bean 的生命周期呢?

其实生命周期的本质是:在哪个时间节点上调用了哪个类当中的哪个方法。

我们需要充分的了解在这个生命线当中,都有哪些特殊的时间节点。

只有我们知道了特殊的时间节点都在哪里了,这样我们才可以确定代码的对应上需要该写到哪里。

有时,我们可能需要在某个特殊的时间点上执行一段特定的代码,从而满足我们的需求,而这段代码可以放到哪个节点上,当生命线走到这里的时候,自然会被调用。

1.2 Bean 的生命周期 "五步"

关于 Bean 生命周期的管理,我们可以参考Spring的源码的:AbstractAutowireCapableBeanFactory类的doCreateBean()方法。 想要进一步了解该源码内容的大家可以移步至✏️✏️✏️Spring6 当中的 Bean 循环依赖的详细处理方案+源码解析-CSDN博客

这里的 Bean的生命周期“五步”是最基本,比较粗略的五步。

  1. 第一步:实例化 Bean
  2. 第二步:对 Bean 当中的属性进行赋值
  3. 第三步:初始化 Bean
  4. 第四步:使用 Bean
  5. 第五步:销毁 Bean

注意点:

  1. 其中的:第三步:初始化 Bean 需要我们通过在 spring.xml 配置文件当中的 标签当中通过 init-method= 属性指定初始化方法 是哪一个方法
  2. 其中的:第四步:销毁 Bean 也是需要我们通过在 spring.xml 配置文件当中的 标签当中的 destroy-method=性指定销毁方法 是哪个方法

实践测试:

准备工作:配置导入 相关的 spring 框架,让 Maven 帮我们导入 spring的相关jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>spring6-006-bean-lifecycle-blog</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.11</version>
        </dependency>


        <!-- junit4 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

第一步: 定义一个 Bean 对象类,这里我们就定义一个 User 的类,来进行测试。

package com.rainbowsea.bean;

public class User {
    private String name;

    public User() {
        System.out.println(" 第一步: User 无参数构造方法调用");
    }


    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("第二步: 为 User 这个 Bean 进行赋值操作");
    }


    /**
     * 这个方法需要自己写,方法名随意,但是注意写好之后,要通过init-method 配给Spring框架,让其知道这个东东
     */
    public void initUserBean() {
        System.out.println("第三步: 对 User Bean 对象进行一个初始化操作");
    }


    /**
     * 这个方法需要自己写,方法名随意,但是注意写好之后,要通过destroy-method配给Spring框架,让其知道这个东东
     */
    public void destroyUserBean() {
        System.out.println("第五步: 对 User Bean 对象进行一个销毁操作");
    }





    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

第二步: 配置相关的 spring.xml 告诉 Spring 框架要做的事情。

上面我们说到,注意点是:

  1. 其中的:第三步:初始化 Bean 需要我们通过在 spring.xml 配置文件当中的 标签当中通过 init-method= 属性指定初始化方法 是哪一个方法
  2. 其中的:第四步:销毁 Bean 也是需要我们通过在 spring.xml 配置文件当中的 标签当中的 destroy-method=性指定销毁方法 是哪个方法

<?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">

    <!--init-method指明Bean的初始化方法是哪个;destroy-method指明Bean的销毁方法是哪个    -->
    <bean id="userBean" class="com.rainbowsea.bean.User" init-method="initUserBean" destroy-method="destroyUserBean">
        <property name="name" value="张三"></property> <!--set注入赋值-->
    </bean>
</beans>

第三步: 运行客户端,模拟测试

注意点:

我们需要手动调用 ClassPathXmlApplicationContext类下面的 close() 方法,正常关闭spring容器才会执行销毁方法。


package com.rainbowsea.test;

import com.rainbowsea.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifecycleTest {

    @Test
    public void testRegisterBean() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println("第四步: 使用 User Bean 对象" + userBean);

        ClassPathXmlApplicationContext classPathXmlApplicationContext = (ClassPathXmlApplicationContext) applicationContext;
        // 注意点:这里的 close()方法是,ClassPathXmlApplicationContext 类才有的,它的ApplicationContext 父类没有。
        // 父类无法调用子类特有的方法,所以这里我们需要强制类型转换回来(向下转型),为子类
        // 只有正常关闭spring容器才会执行销毁方法
        classPathXmlApplicationContext.close();


    }
}
 

执行结果:

总结注意点:

    1. 第一:配置文件中的init-method指定初始化方法。destroy-method指定销毁方法
    2. 第二:只有正常关闭spring容器,bean的销毁方法才会被调用。
    3. 第三:ClassPathXmlApplicationContext类才有close()方法。

1.3 Bean 的生命周期 “七步”

Bean 的生命周期分为“七步”: 是在五步的当中的:第三步初始化Bean 的前后添加上的,Bean 的后处理器。如果加上 Bean 后处理器的话,Bean 的生命周期就是 七步了。

具体七步如下:

  1. 第一步:实例化 Bean
  2. 第二步:对 Bean 当中的属性进行赋值
  3. 第三步:执行 Bean 后处理器的 befor() 方法执行,具体的是:postProcessBeforeInitialization(Object bean, String beanName) 方法
  4. 第四步:初始化 Bean
  5. 第五步:执行 Bean 后处理器的 after() 方法执行,具体的是 postProcessAfterInitialization(Object bean, String beanName) 方法
  6. 第六步:使用 Bean
  7. 第七步:销毁 Bean

第一步:关于 Bean 的后处理器的编写:

关于: bean的后处理器的编写:

编写 bean 后处理器,就是让一个类实现 implements BeanPostProcessor 接口类,同时并且重写其中的before(postProcessBeforeInitialization())和after(postProcessAfterInitialization())方法:


BeanPostProcessor 接口有,两个默认的方法,这两个方法,便是我们需要重写的,来实现我们自己的要的功能。

@Nullable
// 在 Bean 初始化之前被调用
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

@Nullable
// 在 Bean 初始化之后就被调用
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

其中两个参数的作用含义分别是:

    1. Object bean 是该对应的 bean 的对象
    2. String beanName 是该对应 bean 的在spring.xml配置文件当中 id的名字。

这里我们定义一个MyBeanPostProcessor 类作为 Bean 后处理器 实现该 implements BeanPostProcessor 接口,并重写其中的两个默认方法。



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 {
        // Object bean 是 该对应的 bean 的对象
        // String beanName 是该对应 bean 的在配置文件当中 id
        System.out.println("第三步:  Bean 初始化之前执行before()方法");

        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // Object bean 是 该对应的 bean 的对象
        // String beanName 是该对应 bean 的在配置文件当中 id
        System.out.println("第五步:  Bean 初始化之后执行after() 方法");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

第二步:将 Bean 后处理器配置到 spring.xml 文件当中去,告知 Spring 框架,同时进行管理。

大家需要注意的是:该配置Bean后处理器。这个后处理器将作用于当前整个配置文件中所有的bean。

也就是作用于当前这个名为 "spring6.xml" 文件当中的,所配置的所有 bean 都会自动使用上这个我们配置的 bean 后处理器。关于这一点具体说明。我们后面会详细说明的,大家放心。

第三步:模拟客户端,执行程序:


import com.rainbowsea.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifecycleTest {

    @Test
    public void testRegisterBean() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
        User userBean = applicationContext.getBean("userBean", User.class);
        System.out.println("第六步: 使用 User Bean 对象" + userBean);

        ClassPathXmlApplicationContext classPathXmlApplicationContext = (ClassPathXmlApplicationContext) applicationContext;
        // 注意点:这里的 close()方法是,ClassPathXmlApplicationContext 类才有的,它的ApplicationContext 父类没有。
        // 父类无法调用子类特有的方法,所以这里我们需要强制类型转换回来(向下转型),为子类
        // 只有正常关闭spring容器才会执行销毁方法
        classPathXmlApplicationContext.close();


    }
}

上面我们提到了“这个 bean 后处理器的是作用于整个对应的 spring.xml 的配置文件上的所有的 Bean” 的关于这一点,我们下面进行一个简单的验证一下。

我们再创建一个空的类,然后进行一个构造方法的注入,交给 Spring 框架进行管理,是否还是会执行 Bean 处理器。


运行测试:

从运行结果上看,我们可以明显的看出。这个Bean 后处理器是,作用于此 spring.xml 当中对应的整个 Bean 对象的 。简单的来说:就是只要你在某个其中的 spring.xml配置文件当中,启动了,并配置了对应的 Bean后处理器,那么整个 spring.xml 配置文件当中的所有的 Bean 对象都会自动启动上该 Bean 后处理器。

1.4 Bean 的生命周期 “十步”

Bean的生命周期的“十步”就是更加的细化了更加的灵活了

让我们一起来看一下,这所谓的十步,是在上面的七步当中的哪些节点当中,增加了那另外的三步。

十步是在下面这些位置,增加了另外的三步

  1. 首先在 Bean 后处理器的 befor ()执行的前后各自增加了一步,总共为两步
    1. Bean 后处理器的 befor()执行前,增加了 检查 Bean 是否实现了 Aware 的相关接口,并设置相关依赖。
    2. Bean 后处理器的 befor()执行后,增加了检查 Bean 是否实现了 InitializingBean 接口,并调用接口当中的方法
  2. 最后一步,添加在了 销毁 Bean 之前,增加了检查 Bean 是否实现了 DisposableBean 接口,并调用接口当中的方法。

具体十步如下:

  1. 第一步:实例化 Bean
  2. 第二步:对 Bean 当中的属性进行赋值
  3. 第三步: 检查 Bean 是否实现了 Aware 的相关接口,并设置相关依赖。
    1. 其中Aware 的相关接口有三个分别是:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
  4. 第四步:执行 Bean 后处理器的 befor() 方法执行,具体的是:postProcessBeforeInitialization(Object bean, String beanName) 方法
  5. 第五步:检查 Bean 是否实现了 InitializingBean 接口,并调用接口当中的方法
  6. 第六步:初始化 Bean
  7. 第七步:执行 Bean 后处理器的 after() 方法执行,具体的是 postProcessAfterInitialization(Object bean, String beanName) 方法
  8. 第八步:使用 Bean
  9. 第九步:检查 Bean 是否实现了 DisposableBean 接口,并调用接口当中的方法。
  10. 第十步:销毁 Bean

补充说明:

Aware相关的接口包括:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

  • 当Bean实现了BeanNameAware,对应的方法是setBeanName(String name) :Spring会将Bean的名字传递给Bean。

  • 当Bean实现了BeanClassLoaderAware,对应的方法是setBeanClassLoader(ClassLoader classLoader) ; Spring会将加载该Bean的类加载器传递给Bean。

  • 当Bean实现了BeanFactoryAware,对应的方法是setBeanFactory(BeanFactory beanFactory); Spring会将Bean工厂对象传递给Bean。


  • InitializingBean 接口下对应的是:afterPropertiesSet () 方法。


  • DisposableBean 接口下的对应的是:destroy() 方法。

  • 测试以上10步,需要让User类实现5个接口,并实现其中的所有方法:

    • BeanNameAware

    • BeanClassLoaderAware

    • BeanFactoryAware

    • InitializingBean

    • DisposableBean

第一步:定义 Bean 类,我们还是使用这个 User 空白类,进行测试。

第二步:让 让User类实现5个接口(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,InitializingBean,DisposableBean),并实现其中的所有方法:

package com.rainbowsea.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class User implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
    private String name;

    public User() {
        System.out.println("第一步: User 无参数构造方法调用");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("第五步:检查Bean是否实现了InitializingBean 接口,并调用接口方法.afterPropertiesSet执行");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("第九步: 检查 Bean是否实现了DisposableBean接口,并调用接口方法 destroy()  ");
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("第三步:检查是否实现了Aware的相关接口并调用其中的实现接口方法(): Bean 这个类的加载器" + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("第三步:检查是否实现了Aware的相关接口并调用其中的实现接口方法():  生产这个Bean的工厂对象是 " +beanFactory);
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("第三步:检查是否实现了Aware的相关接口并调用其中的实现接口方法():  这个Bean的名称是: " + name);
    }




    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("第二步: 为 User 这个 Bean 进行赋值操作");
    }


    /**
     * 这个方法需要自己写,方法名随意,但是注意写好之后,要通过init-method 配给Spring框架,让其知道这个东东
     */
    public void initUserBean() {
        System.out.println("第六步: 对 User Bean 对象进行一个初始化操作");
    }


    /**
     * 这个方法需要自己写,方法名随意,但是注意写好之后,要通过destroy-method配给Spring框架,让其知道这个东东
     */
    public void destroyUserBean() {
        System.out.println("第十步: 对 User Bean 对象进行一个销毁操作");
    }





    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }


}

配置的 spring.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后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
    <bean class="com.rainbowsea.bean.MyBeanPostProcessor"/>

    <!--init-method指明Bean的初始化方法是哪个;destroy-method指明Bean的销毁方法是哪个    -->
    <bean id="userBean" class="com.rainbowsea.bean.User" init-method="initUserBean" destroy-method="destroyUserBean">
        <property name="name" value="张三"></property> <!--set注入赋值-->
    </bean>


</beans>

对应的 Bean 后处理也是不变的(和生命周期七步是一样的),因为十步是基于七步的基础上细化,添加的。

package com.rainbowsea.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 {
        // Object bean 是 该对应的 bean 的对象
        // String beanName 是该对应 bean 的在配置文件当中 id
        System.out.println("第四步:  Bean 初始化之前执行before()方法");

        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // Object bean 是 该对应的 bean 的对象
        // String beanName 是该对应 bean 的在配置文件当中 id
        System.out.println("第七步:  Bean 初始化之后执行after() 方法");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

最后:运行测试:

2. Bean的作用域不同,管理方式也将是不同的

Spring 根据 Bean 的作用域来选择管理方式。

  1. 对于 singleton (spring 默认的单例)作用域的 Bean ,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成的,以及何时被销毁的,符合上述的生命周期的“五步”,“七步”,“十步” 的流程。
  2. 而对于 prototype(多例) 作用域的 Bean,Spring 只负责创建,当容器创建了 Bean 的实例后,Bean 的实例就交给了客户端代码管理,Spring 容器将不再跟踪其生命周期。不符合上述的生命周期的“五步”,“七步”,“十步” 的流程。

如下:我们把上述的User类的“Bean 的生命周期“十步”演示法当中的 ”spring.xml文件中的配置scope设置为prototype。其他任何内容保持不变。进行演示

运行测试:

从运行结果上看:与之前的 bean 生命周期十步相比较看:我们可以明显的发现。Spring 仅仅到bean 创建后,就不再管理了。而是交给客户端进行自行管理了。spring 不再管理后面的操作了。

2.1 自己new的对象让Spring管理

有些时候可能会遇到这样的需求,某个java对象是我们自己new的,然后我们希望这个对象被Spring容器管理,怎么实现?

准备工作,我们首先创建一个 bean 对象,这里我们创建一个空的 Vip 类,作为 bean 。

我们需要通过 DefaultListableBeanFactory 这个对象,将我们 new 的对象交给 Spring 管理

再通过: DefaultListableBeanFactory 这个对象下的registerSingleton()方法,(这个交给 Spring 管理的bean的id/name 的命名,对于要交给spring管理的对象)
defaultListableBeanFactory.registerSingleton("vipBean",vip);

核心代码:

import com.rainbowsea.bean.User;
import com.rainbowsea.bean.Vip;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanLifecycleTest {

    @Test
    public void test() {
        // 第一步: 我们自己 new 一个对象,方便交给 spring 管理
        Vip vip = new Vip();
        System.out.println(vip);  // 打印一下地址,方便比较


        //  第二步:将以上自己 new 的这个对象纳入 Spring 框架容器当中去管理,半路上交给 Spring来管理
        //  通过 DefaultListableBeanFactory 这个对象,将我们 new 的对象交给 Spring 管理
        DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
        // 通过: registerSingleton()方法,(这个交给 Spring 管理的bean的id/name 的命名,对于要交给spring管理的对象)
        
        defaultListableBeanFactory.registerSingleton("vipBean",vip);

        // 从Spring 容器中获取:通过上述我们 registerSingleton()方法中定义的id,进行一个获取
        Object vipBean = defaultListableBeanFactory.getBean("vipBean");
        System.out.println(vipBean);
        // 单例:地址是一样的。

    }
}

我们是自己new 的对象,半路上交给 Spring 框架进行管理的,所以我们不需要配置spring.xml 的文件上配置相关的 bean 信息。

运行结果:

3. 总结:

  1. 熟悉Bean 的生命周期,各个时间节点上所能做的事情,可以让我们更加灵活的掌握Spring上的运用,更加的灵活,实现我们的业务需要。
  2. Bean 的生命周期 "五步";注意点:初始化 Bean 需要我们通过在 spring.xml 配置文件当中的 标签当中通过 init-method= 属性指定初始化方法 是哪一个方法;销毁 Bean 也是需要我们通过在 spring.xml 配置文件当中的 标签当中的 destroy-method=性指定销毁方法 是哪个方法
  3. Bean 的生命周期分为“七步”;是在五步的当中的:第三步初始化Bean 的前后添加上的,Bean 的后处理器。如果加上 Bean 后处理器的话,Bean 的生命周期就是 七步了。该配置Bean后处理器。这个后处理器将作用于当前整个配置文件中所有的bean。
  4. Bean 的生命周期 “十步”;需要让类实现5个接口(BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,InitializingBean,DisposableBean),并实现其中的所有方法:
  5. singleton (spring 默认的单例)作用域的 Bean ,Spring 能够精确地知道该 Bean 何时被创建,何时初始化完成的,以及何时被销毁的,符合上述的生命周期的“五步”,“七步”,“十步” 的流程。
  6. Bean的作用域不同,管理方式也将是不同的;而对于 prototype(多例) 作用域的 Bean,Spring 只负责创建,不符合上述的生命周期的“五步”,“七步”,“十步” 的流程。 singleton (spring 默认的单例)作用域的 Bean 符合上述的生命周期的“五步”,“七步”,“十步” 的流程。
  7. 自己new的对象让Spring管理(将以上自己 new 的这个对象纳入 Spring 框架容器当中去管理,半路上交给 Spring来管理);通过: DefaultListableBeanFactory 这个对象下的registerSingleton()方法,(这个交给 Spring 管理的bean的id/name 的命名,对于要交给spring管理的对象)

4. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

热门相关:极品仙医在都市   国民女神:重生王牌千金   我向斐少撒个娇   学霸你女朋友掉了   首席的亿万老婆