Spring——Spring的后处理器

一、 Bean 实例化的基本流程

在之前我们说 BeanFactory 和 ApplicationContext 的时候,曾说过两个很重要的 map 集合 beanDefinitionMap 和 singletonObjects,这两个一个是存储 bean 的定义信息的,一个是存储成品 bean 的

beanDefinitionMap :存储 bean 定义对象的 map,我们在 xml 中定义的 bean 的内容,都会被读取并且存储到一个个的 BeanDefinition 对象中,供容器创建对象使用

singletonObjects :Spring 创建好的 bean 对象存储的地方,通过 getBean 方法获取对象就是从这里获取的

Spring 在启动的时候,首先是会去读取配置文件的内容,将配置文件中的 bean 标签封装为一个个的 BeanDefinition 对象存储到 beanDefinitionMap 中,然后再通过遍历 beanDefinitionMap,获取 BeanDefinition 对象并解析,利用反射和工厂创建 bean 对象,之后再存储到 singletonObjects 中供使用者使用

实例化流程图:

在这里插入图片描述

上面的过程自动发生自动进行。Spring 针对上述的流程,提供了对外的接口,使我们开发人员也可以介入到 Bean 的实例化流程中,已达到动态注册 BeanDefinition 、修改 BeanDefinition 和 修改 Bean 的操作。这就是 Spring 提供的后处理器

Spring 提供的后处理分为两种:

  1. BeanFactoryPostProcessor:Bean 工厂后处理器,在 BeanDefinition 都存储到 beanDefinitionMap 之后,bean 进行实例化之前执行。一般是用于向 beanDefinitionMap 中注册 BeanDefinition 或者修改 beanDefinitionMap 中的 BeanDefinition
  2. BeanPostProcessor:Bean 后处理器,在一个 Bean 完成实例化,但是还没有存储进 singletonObjects 之前执行,用来动态的修改 Bean

这两种后处理器,BeanFactoryPostProcessor 只会执行一次针对 beanDefinitionMap 做处理,而 BeanPostProcessor 会执行多次,他会针对每一个 bean 都做处理

二、BeanFactoryPostProcessor

这是一个接口,我们在使用的时候只需要实现这个接口,并将接口的实现类注册到 Spring 容器中,Spring 容器就会自动帮我们调用接口中的方法去对 beanDefinitionMap 进行操作

在这里插入图片描述

这个接口中只提供了一个方法 postProcessBeanFactory,方法的参数 ConfigurableListableBeanFactory 是 BeanFactory 的一个子接口,实际的实现类还是 DefaultListableBeanFactory,下面我们定义一个类来实现接口,并注册类

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor 的 postProcessBeanFactory 方法执行");
    }
}
<bean class="com.fang.processor.MyBeanFactoryPostProcessor"/>

只需要将我们定义的 BeanFactoryPostProcessor 实现类注册到 Spring 中,Spring 就会自动调用我们这个类中的方法

2.1 BeanDefinition 的修改

我们知道 BeanDefinition 是存储在 beanDefinitionMap 中,而 beanDefinitionMap 是存储在 BeanFactory 中,现在我们可以在 postProcessBeanFactory 方法中获取到 ConfigurableListableBeanFactory 那么是不是就可以获取到 beanDefinitionMap 然后对 beanDefinitionMap 中的 BeanDefinition 进行修改呢?

实际上获取 beanDefinitionMap 是不可行的,出于安全考虑,BeanFactory 并不提供直接获取 beanDefinitionMap 的权限,但是 postProcessBeanFactory 方法中的 ConfigurableListableBeanFactory 提供了获取某个 BeanDefinition 的权限,调用 ConfigurableListableBeanFactory 的 getBeanDefinition 方法,可以根据 key 获取一个 BeanDefinition

<!-- xml 配置 -->
<bean id="userDao" class="com.fang.dao.impl.UserDaoImpl"/>
//BeanFactoryPostProcessor 逻辑
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userDao");
        beanDefinition.setBeanClassName("com.fang.service.impl.UserServiceImpl");
    }
}
//测试代码逻辑
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Object bean = applicationContext.getBean("userDao");
System.out.println("bean = " + bean);

上述的代码,我们在 xml 中配置了一个 UserDao 的 bean,之后在 MyBeanFactoryPostProcessor 中将 userDao 对应的 BeanDefinition 的类路径修改为 com.fang.service.impl.UserServiceImpl

之后我们获取 userDao 获取到的将是一个 UserServiceImpl

在这里插入图片描述

2.2 BeanDefinition 的注册

BeanDefinition 的注册意思就是向 beanDefinitionMap 集合中添加 BeanDefinition 对象,这样 Spring 容器也会根据我们添加的 BeanDefinition 去创建对象,我们可以不用在 xml 文件中写 bean

下面的代码演示怎么使用后处理器向 beanDefinitionMap 中注册 BeanDefinition

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //创建 BeanDefinition 对象
        BeanDefinition beanDefinition = new RootBeanDefinition("com.fang.dao.impl.UserDaoImpl");
        //将 ConfigurableListableBeanFactory 转化为 DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        //注册 BeanDefinition
        defaultListableBeanFactory.registerBeanDefinition("userDao", beanDefinition);
    }
}

这里主要分三步:

  1. 创建一个 BeanDefinition 对象:

    BeanDefinition 实际上是一个接口,创建这个接口的对象常用的是他的实现类 RootBeanDefinition。构造器中传递类的全路径

  2. 转化 BeanFactory 的类型:

    处理器方法中提供的 ConfigurableListableBeanFactory 接口不存在注册 BeanDefinition 的方法,要注册 BeanDefinition 我们需要将其转化为他的实现类 DefaultListableBeanFactory,且项目中本来存在的 BeanFactory 就是 DefaultListableBeanFactory,这里直接强转即可

  3. 注册 BeanDefinition

    调用 registerBeanDefinition 方法注册 BeanDefinition 其中第一个参数是 beanName,也是集合中 BeanDefinition 的 key

通过上述的步骤,我们不需要在 xml 中注册 bean,也可以将 BeanDefinition 注册到 beanDefinitionMap 中,最终 Spring 也会根据 beanDefinitionMap 中的 BeanDefinition 对象创建 bean

需要注意的是,当我们在 xml 中提供了相同 beanName 的 bean 标签时,后处理器注册的 BeanDefinition 会将原本的 BeanDefinition 给覆盖掉

BeanDefinitionRegistryPostProcessor

其实对于 BeanFactory 的注册,Spring 提供了 BeanFactoryPostProcessor 的一个子接口 BeanDefinitionRegistryPostProcessor,这个接口中提供了一个 postProcessBeanDefinitionRegistry 方法,这个方法参数中的 BeanDefinitionRegistry 存在注册 BeanDefinition 的方法

在这里插入图片描述

我们需要注册 BeanDefinition 的话,实现这个接口更加方便

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    //子接口提供的更便于注册 BeanDefinition 的方法
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinition beanDefinition = new RootBeanDefinition("com.fang.dao.impl.UserDaoImpl");
        registry.registerBeanDefinition("userDao", beanDefinition);
    }

    //父接口的方法
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}
<bean class="com.fang.processor.MyBeanDefinitionRegistryPostProcessor"/>

这样我们不需要再额外去对 beanFactory 做转换操作

补充:

如果 MyBeanFactoryPostProcessor 和 MyBeanDefinitionRegistryPostProcessor 在容器中都存在的话,在启动的时候,执行有先后循序,分别是:

子接口的 postProcessBeanDefinitionRegistry 方法 → 子接口的 postProcessBeanFactory 方法 → 父接口的 postProcessBeanFactory 方法

这个我们可以在三个方法中都打印日志来验证

在这里插入图片描述

三、 BeanPostProcessor

Spring 遍历 beanDefinitionMap 实例化 bean 后,最终会被存放到单例池中,在存放进单例池之前,bean 还会有一个初始化过程,对 bean 的属性进行填充,执行初始化方法等,在这个初始化的过程中,Spring 提供了一个对外的接口,用于处理 bean 的内容,这个接口就是 BeanPostProcessor

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;
	}

}

接口的内部提供了两个默认方法,postProcessBeforeInitialization 和 postProcessAfterInitialization,其中前者是 bean 执行初始化方法之前执行的,后者是 bean 执行初始化方法之后执行,两个方法都不是必须要实现的

我们只需要实现 BeanPostProcessor,重写上面的两个方法,并且将实现类注册到 Spring 容器中,Spring 在 bean 创建完毕后就会自动去调用这两个方法了

public class MyBeanPostProcesser implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization执行");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization执行");
        return bean;
    }
}
<bean class="com.fang.processor.MyBeanPostProcesser"/>

两个方法都有两个参数,一个是当前的 bean 对象,一个是 bean 的名字,这里就可以对 bean 对象执行我们想要的操作了

spring 执行的步骤就是:对象创建 → 属性注入 → before 方法 → 初始化方法 → after 方法

在这里插入图片描述

每一个 bean 创建后,都会执行一次 BeanPostProcessor 中的两个方法

四、 完善实例化流程图

了解了两个后处理器后,我们就可以对上面的 Bean 实例化的流程图进行进一步的完善
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值