Spring高级特性(3)----后置处理器及SpringBean的生命周期

Spring提供了两种后处理bean的扩展接口,分别为 BeanPostProcessor 和BeanFactoryPostProcessor,两者在使用上是有所区别的。工厂在前,bean对象在后。在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做⼀些事情,在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做⼀些事情。
注意:对象不一定是springbean,但springbean⼀定是个对象

(1)BeanPostProcessor

BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean。该接⼝提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行,具体这个初始化方法指的是什么方法,类似我们在定义bean时,xml中定义的init-method所指定的方法。

public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

定义⼀个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进⾏处理。如果要对具体的某个bean处理,可以通过方法的形参进行判断,两个类型参数分别为Object和String,第⼀个参数是每个bean的实例,第⼆个参数是每个bean的name或者id属性的值。所以我们可以通过第⼆个参数,来判断我们将要处理的具体的bean。如下图,我们想要对lazyBean对象在初始化前后进行处理,这里的初始化就包括init-method属性中指定的initMethod方法。
注意:处理是发生在Spring容器的实例化和依赖注入之后。

<bean id="lazyBean" class="com.nanmao.LazyBean" init-method="initMethod" destroy-method="destroyMethod"/>
/**
 * 拦截实例化后的对象(实例化并且属性注入了),可以根据beanName来对特定的bean进行初始化前后的处理
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("lazyBean".equals(beanName)){
            System.out.println("MyBeanPostProcessor 拦截bean 初始化之前Before处理");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("lazyBean".equals(beanName)){
            System.out.println("MyBeanPostProcessor 拦截bean 初始化之后After处理");
        }
        return bean;
    }
}

我们来看下SpringBean的生命周期,如下图。
在这里插入图片描述
承接上面的代码,以LazyBean作为演示,实现BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean、BeanPostProcessor对应的方法,我们来打印下bean生命周期中的处理顺序:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class LazyBean implements BeanNameAware, BeanFactoryAware,
        ApplicationContextAware, InitializingBean, DisposableBean {
    public LazyBean() {
        System.out.println("lazyBean无参构造初始化------");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("bean id是:" + s);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("创建bean的上层bean工厂是:" + beanFactory);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("高级容器接口ApplicationContext:" + applicationContext);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean 接口中afterPropertiesSet方法");
    }

    public void initMethod() {
        System.out.println("xml中init-method属性对应的初始化方法");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("注解@PostConstruct对应的初始方法");
    }

    //===================bean的销毁相关方法===================
    
    public void destroyMethod() {
        System.out.println("xml中destroy-method属性对应的销毁方法");
    }
    @PreDestroy
    public void preDestroy() {
        System.out.println("注解@PreDestroy对应的销毁方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean接口中的销毁方法");
    }
}
public class IocXmlTest {
    @Test
    public void TestIocContainer() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object lazyBean = applicationContext.getBean("lazyBean");
        System.out.println(lazyBean);
        System.out.println("===============销毁方法==============");
        applicationContext.close();
    }
}

控制台输出:

lazyBean无参构造初始化------
bean id是:lazyBean
创建bean的上层bean工厂是:org.springframework.beans.factory.support.DefaultListableBeanFactory@42eca56e: defining beans [myBeanPostProcessor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,accountDao,transferService,connectionUtils,transactionManager,proxyFactory,lazyBean,companyBean]; root of factory hierarchy
高级容器接口ApplicationContext:org.springframework.context.support.ClassPathXmlApplicationContext@6d1e7682, started on Sun Aug 29 23:08:18 CST 2021
MyBeanPostProcessor 拦截bean 初始化之前Before处理
注解@PostConstruct对应的初始方法
InitializingBean 接口中afterPropertiesSet方法
xml中init-method属性对应的初始化方法
MyBeanPostProcessor 拦截bean 初始化之后After处理
com.nanmao.LazyBean@19d37183
===============销毁方法==============
注解@PreDestroy对应的销毁方法
DisposableBean接口中的销毁方法
xml中destroy-method属性对应的销毁方法

注意:注解@PostConstruct和注解@PreDestroy的执行过程要早于xml中init-method属性和destroy-method属性配置的对应的方法

(2) BeanFactoryPostProcessor

BeanFactory级别的处理,是针对整个Bean的工厂进行处理,典型应用:PropertyPlaceholderConfigurer。

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

在这里插入图片描述
此接口只提供了⼀个方法,方法参数为ConfigurableListableBeanFactory。该参数类型定义了⼀些方法,其中有个方法名为getBeanDefinition的⽅法,我们可以根据此方法,找到我们定义bean 的BeanDefinition对象。然后我们可以对定义的属性进行修改,以下是BeanDefinition中的方法:

在这里插入图片描述
方法法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。
BeanDefinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个JavaBean,这个JavaBean 就是 BeanDefinition。
注意:调用BeanFactoryPostProcessor方法时,这时候bean还没有实例化,此时bean刚被解析成BeanDefinition对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值