Spring 使用指南 ~ 3Spring 中 bean 的生命周期详解

Posted 戴泽supp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 使用指南 ~ 3Spring 中 bean 的生命周期详解相关的知识,希望对你有一定的参考价值。

Spring 中 bean 的生命周期详解

一、bean 的生命周期图解

二、bean 创建时使用 Spring 的资源

  • 实现 aware 类型接口的 bean,可以在 bean 实例化的时候获取到一些相对应的资源,如实现 BeanNameAware 的 bean,就可以获取到 beanName。
  • Spring 自带的 aware 类型的接口有很多,下面只列举了常用的三个(ApplicationContextAware 是用的最多的一个)

1、BeanNameAware

  • 使用 BeanNameAware 接口来获取 beanName

示例

package com.luo.spring.guides.beanlifecycle.aware.name;

import org.springframework.beans.factory.BeanNameAware;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:37
 * @description :
 */
public class NamedSinger  implements BeanNameAware 
    private String name;

    /** @Implements @link BeanNameAware#setBeanName(String) */
    public void setBeanName(String beanName) 
        this.name = beanName;
    

    public void sing() 
        System.out.println("Singer [" + name + "] - sing()");
    

<?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 id="namedSinger" class="com.luo.spring.guides.beanlifecycle.aware.name.NamedSinger"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.aware.name;

import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:38
 * @description :
 */
public class Main 
    public static void main(String[] args) 
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("beanlifecycle/aware/name/app-context-name.xml");
        ctx.refresh();

        NamedSinger bean = (NamedSinger) ctx.getBean("namedSinger");
        bean.sing();

        ctx.close();
    

输出

Singer [namedSinger] - sing()

2、BeanClassLoaderAware

package com.luo.spring.guides.beanlifecycle.aware.classloader;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.stereotype.Component;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:51
 * @description :
 */
@Component
public class SingerClassLoaderBean implements BeanClassLoaderAware 

    private ClassLoader classLoader;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) 
        this.classLoader = classLoader;
    

    public void print()
        System.out.println(classLoader);
    

测试

package com.luo.spring.guides.beanlifecycle.aware.classloader;

import com.luo.spring.guides.iocdi.annotation.field.Singer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author : archer
 * @date : Created in 2022/12/6 15:52
 * @description :
 */
public class Main 

    @Configuration
    @ComponentScan(basePackages = "com.luo.spring.guides.beanlifecycle.aware.classloader")
    public static class ClassloaderConfiguration

    public static void main(String... args) 
        ApplicationContext ctx = new AnnotationConfigApplicationContext
                (ClassloaderConfiguration.class);
        SingerClassLoaderBean singerClassLoaderBean = ctx.getBean("singerClassLoaderBean", SingerClassLoaderBean.class);


        singerClassLoaderBean.print();
    

输出

jdk.internal.loader.ClassLoaders$AppClassLoader@4e25154f

3、ApplicationContextAware

package com.luo.spring.guides.beanlifecycle.aware.applicationcontext;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Created by iuliana.cosmina on 2/22/17.
 */
@Component
public class Singer implements ApplicationContextAware 

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
        this.applicationContext = applicationContext;
    


    public void sing() 
		System.out.println(applicationContext.getId());
    

测试

package com.luo.spring.guides.beanlifecycle.aware.applicationcontext;

import com.luo.spring.guides.beanlifecycle.aware.classloader.SingerClassLoaderBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author : archer
 * @date : Created in 2022/12/8 14:20
 * @description :
 */
public class Main 

    @Configuration
    @ComponentScan(basePackages = "com.luo.spring.guides.beanlifecycle.aware.applicationcontext")
    public static class MConfiguration 
    

    public static void main(String... args) 
        ApplicationContext ctx = new AnnotationConfigApplicationContext(MConfiguration.class);
        Singer singer = (Singer) ctx.getBean("singer");
        singer.sing();
    

输出

org.springframework.context.annotation.AnnotationConfigApplicationContext@45820e51

三、bean 创建时调用特定方法

1、@PostConstruct

package com.luo.spring.guides.beanlifecycle.init.postconstruct;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import javax.annotation.PostConstruct;

public class SingerWithJSR250 
    private static final String DEFAULT_NAME = "Eric Clapton";

    private String name;
    private int age = Integer.MIN_VALUE;

    public void setName(String name) 
        this.name = name;
    

    public void setAge(int age) 
        this.age = age;
    

    @PostConstruct
    private void init() throws Exception 
        System.out.println("Initializing bean");

       if (name == null) 
            System.out.println("Using default name");
            name = DEFAULT_NAME;
        

        if (age == Integer.MIN_VALUE) 
            throw new IllegalArgumentException(
                    "You must set the age property of any beans of type " + 
                    SingerWithJSR250.class);
        
    

    public String toString() 
        return "\\tName: " + name + "\\n\\tAge: " + age;
    

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context 
          http://www.springframework.org/schema/context/spring-context.xsd"
       default-lazy-init="true">

    <context:annotation-config/>

    <bean id="singerOne"
          class="com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250"
          p:name="John Mayer" p:age="39"/>

    <bean id="singerTwo"
          class="com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250"
          p:age="72"/>

    <bean id="singerThree"
          class="com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250"
          p:name="John Butler"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.init.postconstruct;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 15:26
 * @description :
 */
public class Main 
    public static void main(String... args) 
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:beanlifecycle/init/app-context-postconstruct.xml");
        ctx.refresh();

        getBean("singerOne", ctx);
        getBean("singerTwo", ctx);
        getBean("singerThree", ctx);

        ctx.close();
    

    private static SingerWithJSR250 getBean(String beanName, ApplicationContext ctx) 
        try 
            SingerWithJSR250 bean = (SingerWithJSR250) ctx.getBean(beanName);
            System.out.println(bean);
            return bean;
         catch (BeanCreationException ex) 
            System.out.println("An error occured in bean configuration: "
                    + ex.getMessage());
            return null;
        
    

输出

Initializing bean
Name: John Mayer
Age: 39
Initializing bean
Using default name
Name: Eric Clapton
Age: 72
Initializing bean
An error occured in bean configuration: Error creating bean with name ‘singerThree’: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: You must set the age property of any beans of type class com.luo.spring.guides.beanlifecycle.init.postconstruct.SingerWithJSR250

2、InitializingBean

package com.luo.spring.guides.beanlifecycle.init.initialzingbean;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class SingerWithInterface implements InitializingBean 
    private static final String DEFAULT_NAME = "Eric Clapton";

    private String name;
    private int age = Integer.MIN_VALUE;

    public void setName(String name) 
        this.name = name;
    

    public void setAge(int age) 
        this.age = age;
    

    public void afterPropertiesSet() throws Exception 
        System.out.println("Initializing bean");

        if (name == null) 
            System.out.println("Using default name");
            name = DEFAULT_NAME;
        

        if (age == Integer.MIN_VALUE) 
            throw new IllegalArgumentException(
                    "You must set the age property of any beans of type " 
                    + SingerWithInterface.class);
        
    

    public String toString() 
        return "\\tName: " + name + "\\n\\tAge: " + age;
    

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-lazy-init="true">

    <bean id="singerOne"
          class="com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface"
          p:name="John Mayer" p:age="39"/>

    <bean id="singerTwo"
          class="com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface"
          p:age="72"/>

    <bean id="singerThree"
          class="com.luo.spring.guides.beanlifecycle.init.initialzingbean.SingerWithInterface"
          p:name="John Butler"/>
</beans>

测试

package com.luo.spring.guides.beanlifecycle.init.initialzingbean;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/8 15:33
 * @description :
 */
public class Main 

    public static void main(String... args) 
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("beanlifecycle/init/app-context-initializingbean.xml");
        ctx.refresh();

        getBean("singerOne", ctx);
        getBean("singerTwo", ctx);
        getBean以上是关于Spring 使用指南 ~ 3Spring 中 bean 的生命周期详解的主要内容,如果未能解决你的问题,请参考以下文章

sping揭秘3Spring容器中bean默认是保持一个实例

23_3spring

3Spring Cloud - Eureka(高可用Eureka Server集群)

3Spring的AOP详解和案例

3Spring 源码学习 ~ 默认标签的解析之 Bean 标签解析

老王读Spring IoC-3Spring bean 的创建过程