夯实spring(二十二):springBean生命周期

本文详细阐述了Spring容器中Bean从定义、注册、实例化、初始化到销毁的全过程,包括BeanDefinition的类别、注册操作、BeanPostProcessor的作用以及不同阶段的回调方法。重点介绍了如何通过BeanPostProcessor干预Bean的生命周期和使用自定义构造器实例化。

一.bean生命周期的理解

spring把放到容器里的简单的java对象(pojo)称作bean。bean生命周期大概就是从一个bean信息定义到bean注册到bean实例化到bean初始化到bean销毁的过程。而spring为我们提供了一个BeanPostProcessor接口。还有很多子接口,这些接口中提供了很多方法,spring在bean生命周期的不同阶段,会调用上面这个列表中的BeanPostProcessor中的一些方法,来对生命周期进行扩展和对bean的生命周期进行干预。

1,bean信息定义阶段

spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。不管是是通过xml
配置文件的 标签,还是通过注解配置的 @Bean ,还是 @Compontent 标注的类,还是扫描得到
的类,它最终都会被解析成一个BeanDefinition对象,最后我们的Bean工厂就会根据这份Bean的定义
信息,对bean进行实例化、初始化等等操作。你可以把BeanDefinition丢给Bean工厂,然后Bean工厂就会根据这个信息帮你生产一个Bean实例,拿
去使用。
BeanDefinition里面里面包含了bean定义的各种信息,如:bean对应的class、scope、lazy信息、
dependOn信息、autowireCandidate(是否是候选对象)、primary(是否是主要的候选者)等信
息。

## 1.1 BeanDefinition相关的几个类和接口:

RootBeanDefinition类

	表示根bean定义信息通常bean中没有父bean的就使用这种表示

ChildBeanDefinition类

	表示子bean定义信息如果需要指定父bean的,可以使用ChildBeanDefinition来定义子bean的配置信息,里面有个parentName 属性,用来指定父bean的名称。

GenericBeanDefinition类

通用的bean定义信息既可以表示没有父bean的bean配置信息,也可以表示有父bean的子bean配置信息,这个类里面也有parentName属性,用来指定父bean的名称。

ConfigurationClassBeanDefinition类

表示通过配置类中@Bean方法定义bean信息,可以通过配置类中使用@Bean来标注一些方法,通过这些方法来定义bean,这些方法配置的bean信息最后会转换为ConfigurationClassBeanDefinition类型的对象

AnnotatedBeanDefinition接口

表示通过注解的方式定义的bean信息

BeanDefinitionBuilder

构建BeanDefinition的工具类,spring中为了方便操作BeanDefinition,提供了一个类BeanDefinitionBuilder ,内部提供了很多静态方法,通过这些方法可以非常方便的组装BeanDefinition对象。

1.2 来几个案列

/**
 * 简单一个bean
 * 
 */
public class Car {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                '}';
    }
}

例1:组装一个简单的bean

public class Test1 {
    public static void main(String[] args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        //获取BeanDefinition
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);
    }
}

输出:Root bean: class [beanLife.bean.Car]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null

例2: 组装一个有属性的bean

public class Test2 {
    public static void main(String[] args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName())
                .addPropertyValue("name","大众").setLazyInit(true);
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();

        System.out.println(beanDefinition);

        //创建spring容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //调用registerBeanDefinition向容器中注册bean
        beanFactory.registerBeanDefinition("MyCar",beanDefinition);
        Car bean = beanFactory.getBean("MyCar", Car.class);
        System.out.println(bean);
    }
}
输出:
`Root bean: class [beanLife.bean.Car]; scope=; abstract=false; lazyInit=true; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
Car{name='大众'}`

2,bean注册阶段

bean注册阶段需要用到一个非常重要的接口:BeanDefinitionRegistry。这个接口中定义了注册bean常用到的一些方法,如下:

public interface BeanDefinitionRegistry extends AliasRegistry {
/**
* 注册一个新的bean定义
* beanName:bean的名称
* beanDefinition:bean定义信息
*/
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
/**
* 通过bean名称移除已注册的bean
* beanName:bean名称
*/
void removeBeanDefinition(String beanName) throws
NoSuchBeanDefinitionException;
/**
* 通过名称获取bean的定义信息
* beanName:bean名称
*/
BeanDefinition getBeanDefinition(String beanName) throws
NoSuchBeanDefinitionException;
/**
* 查看beanName是否注册过
*/
boolean containsBeanDefinition(String beanName);
/**
* 获取已经定义(注册)的bean名称列表
*/
String[] getBeanDefinitionNames();
/**
* 返回注册器中已注册的bean数量
*/
int getBeanDefinitionCount();
/**
* 确定给定的bean名称或者别名是否已在此注册表中使用
* beanName:可以是bean名称或者bean的别名
*/
boolean isBeanNameInUse(String beanName);
}

spring中BeanDefinitionRegistry接口有一个唯一的实现类:

org.springframework.beans.factory.support.DefaultListableBeanFactory

例:

    @Test
    public void test1(){
        //创建一个bean工厂,这个默认实现了BeanDefinitionRegistry接口,所以也是一个bean注册器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //定义一个bean
        GenericBeanDefinition nameBdf = new GenericBeanDefinition();
        nameBdf.setBeanClass(String.class);
        nameBdf.getConstructorArgumentValues().addIndexedArgumentValue(0,"刘德华");
        //将bean注册到容器中
        factory.registerBeanDefinition("name",nameBdf);
        //通过bean名获取BeanDefinition
        System.out.println(factory.getBeanDefinition("name"));
        //通过名称判断是否注册过BeanDefinition
        System.out.println(factory.containsBeanDefinition("name"));
        //获取所有注册的名称
        System.out.println(Arrays.asList(factory.getBeanDefinitionNames()));
        //获取已注册的BeanDefinition的数量
        System.out.println(factory.getBeanDefinitionCount());
        //判断指定的name是否使用过
        System.out.println(factory.isBeanNameInUse("name"));
        //别名相关方法
        //为name注册2个别名
        factory.registerAlias("name","alias-name-1");
        factory.registerAlias("name","alias-name-2");
        ////判断alias-name-1是否已被作为别名使用
        System.out.println(factory.isAlias("alias-name-1"));
        //通过名称获取对应的所有别名
        System.out.println(Arrays.asList(factory.getAliases("name")));
        //最后我们再来获取一下这个bean
        System.out.println(factory.getBean("name"));
    }

输出:

Generic bean: class [java.lang.String]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null
true
[name]
1
true
true
[alias-name-2, alias-name-1]
刘德华

3,bean实例化阶段

分2个小的阶段

  1. Bean实例化前操作
  2. Bean实例化操作

3.1Bean实例化前操作

Bean实例化之前会调用一段代码:

@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?>
beanClass, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp =(InstantiationAwareBeanPostProcessor) bp;
			Object result = ibp.postProcessBeforeInstantiation(beanClass,beanName);
		if (result != null) {
			return result;
		}
	}
}
return null;
}

这段代码在bean实例化之前给开发者留了个口子,开发者自己可以在这个地方直接去创建一个对象作
为bean实例,而跳过spring内部实例化bean的过程。该代码轮询 beanPostProcessors 列表,如果类型是
InstantiationAwareBeanPostProcessor , 尝试调用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 获取bean的实例对象,如果能够获取到,那么将返回值作为当前bean的实例,那么spring自带的实例化bean的过程就被跳过了。

来个案例:

public class InstantiationAwareBeanPostProcessorTest {
    @Test
    public void test1() {
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//添加一个BeanPostProcessor:InstantiationAwareBeanPostProcessor
        factory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessor() {
            //@1
            @Nullable
            @Override
            public Object postProcessBeforeInstantiation(Class<?> beanClass,
                                                         String beanName) throws BeansException {
                System.out.println("调用postProcessBeforeInstantiation()");
//发现类型是Car类型的时候,硬编码创建一个Car对象返回
                if (beanClass == Car.class) {
                    Car car = new Car();
                    car.setName("保时捷");
                    return car;
                }
                return null;
            }
        });
//定义一个car bean,车名为:奥迪
        AbstractBeanDefinition carBeanDefinition = BeanDefinitionBuilder.
                genericBeanDefinition(Car.class).
                addPropertyValue("name", "奥迪"). //@2
                getBeanDefinition();
        factory.registerBeanDefinition("car", carBeanDefinition);
//从容器中获取car这个bean的实例,输出
        System.out.println(factory.getBean("car"));
    }
}

输出:

调用postProcessBeforeInstantiation()
Car{name='保时捷'}

3.2 Bean实例化操作

这个过程会通过反射来调用bean的构造器来创建bean的实例。
具体需要使用哪个构造器,spring为开发者提供了一个接口,允许开发者自己来判断用哪个构造器。

这个过程会调用 SmartInstantiationAwareBeanPostProcessor接口的determineCandidateConstructors 方
法,这个方法会返回候选的构造器列表,也可以返回空。源码如下:

@Nullable
default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass,
String beanName)
throws BeansException {
	return null;
}

我们可以重写InstantiationAwareBeanPostProcessor#determineCandidateConstructors方法来决定使用bean的哪个构造方法来实例化我们的bean。

4,Bean初始化阶段

这个阶段分为几个小的阶段:
1.Bean Aware接口回调
2.Bean初始化前操作
3.Bean初始化操作
4.Bean初始化后操作

## 4.1 Bean Aware接口回调

我们的bean可以实现BeanNameAware, BeanClassLoaderAware,BeanFactoryAware 这些接口,这些接口会按照下面顺序依次进行调用并可以帮助我们在bean创建完成后注入:

	BeanNameAware:将bean的名称注入进去
	BeanClassLoaderAware:将BeanClassLoader注入进去
	BeanFactoryAware:将BeanFactory注入进去

比如:

public class AwareBean implements BeanNameAware, BeanClassLoaderAware,
BeanFactoryAware {
	@Override
	public void setBeanName(String name) {
		System.out.println("setBeanName:" + name);
	}
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("setBeanFactory:" + beanFactory);
	}
	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		System.out.println("setBeanClassLoader:" + classLoader);
	}
}
##  4.2 Bean初始化前操作

这个阶段会调用 BeanPostProcessor的postProcessBeforeInitialization 方法,若返回null,当前方法将结
束。
接口BeanPostProcessor有两个实现类:

org.springframework.context.support.ApplicationContextAwareProcessor
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

如果bean实现了下面的接口 ,org.springframework.context.support.ApplicationContextAwareProcessor这个接口的#postProcessBeforeInitialization 中会依次调用下面接口中的方法,将 Aware 前缀对应的对象注入到bean实例中。

EnvironmentAware:注入Environment对象
EmbeddedValueResolverAware:注入EmbeddedValueResolver对象
ResourceLoaderAware:注入ResourceLoader对象
ApplicationEventPublisherAware:注入ApplicationEventPublisher对象
MessageSourceAware:注入MessageSource对象
ApplicationContextAware:注入ApplicationContext对象

如:

public class Bean1 implements EnvironmentAware, EmbeddedValueResolverAware,
ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware,
ApplicationContextAware {
	@PostConstruct
	public void postConstruct1() {
		System.out.println("postConstruct1()");
	}
	@PostConstruct
	public void postConstruct2() { 
		System.out.println("postConstruct2()");
	}
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
	throws BeansException {
		System.out.println("setApplicationContext:" + applicationContext);
	}
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher
	applicationEventPublisher) {
		System.out.println("setApplicationEventPublisher:" +
		applicationEventPublisher);
	}
	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		System.out.println("setEmbeddedValueResolver:" + resolver);
	}
	@Override
	public void setEnvironment(Environment environment) {
		System.out.println("setEnvironment:" + environment.getClass());
	}
	@Override
	public void setMessageSource(MessageSource messageSource) {
		System.out.println("setMessageSource:" + messageSource);
	}
	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		System.out.println("setResourceLoader:" + resourceLoader);
	}
}
## 4.3 Bean初始化阶段

2个步骤

  1. 调用InitializingBean接口的afterPropertiesSet方法
  2. 调用定义bean的时候指定的初始化方法。

InitializingBean接口

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

如:

public class Service implements InitializingBean{
	public void init() {
		System.out.println("调用init()方法");
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("调用afterPropertiesSet()");
	}
}
## 4.4 Bean初始化后阶段

会调用BeanPostProcessor接口的postProcessAfterInitialization方法 ,返回null的时候,会中断上
面的操作。

5,Bean销毁阶段

触发bean销毁的几种方式

  1. 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean
  2. 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons
  3. 调用ApplicationContext中的close方法

Bean销毁阶段会依次执行

  1. 轮询beanPostProcessors列表,如果是DestructionAwareBeanPostProcessor这种类型的,会调
    用其内部的postProcessBeforeDestruction方法.
  2. 如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中
    的destroy方法
  3. 调用bean自定义的销毁方法

DestructionAwareBeanPostProcessor接口:

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {
/**
* bean销毁前调用的方法
*/
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;
/**
* 用来判断bean是否需要触发postProcessBeforeDestruction方法
*/
default boolean requiresDestruction(Object bean) {
	return true;
}
}

DisposableBean接口:

public interface DisposableBean {
	void destroy() throws Exception;
}

触发@PreDestroy标注的方法被调用:
这个注解是在 CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction 中
被处理的

如:

public class ServiceA implements DisposableBean {
	public ServiceA() {
		System.out.println("创建ServiceA实例");
	}
	@PreDestroy
	public void preDestroy1() {
		System.out.println("preDestroy1()");
	}
	@PreDestroy
	public void preDestroy2() {
		System.out.println("preDestroy2()");
	}
	@Override
	public void destroy() throws Exception {
		System.out.println("DisposableBean接口中的destroy()");
	}
	//自定义的销毁方法
	public void customDestroyMethod() { //@1
		System.out.println("我是自定义的销毁方法:customDestroyMethod()");
	}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值