深入Spring底层透析后置处理器之豁然开朗篇

前言

看这篇文章之前,需要了解Bean创建的过程,本篇文章是接着bean创建的基本流程的续写
Bean创建的基本过程:http://t.csdn.cn/1lK2d


Spring的后置处理器

熟悉Bean创建的基本流程是前提

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。Spring主要有两种后处理器:

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行
  • BeanPostProcessor:Bean后处理器,一般在Bean实例化之后,填充到单例池singletonObjects之前执行

那Spring的后置处理器有什么用处呢?
不知道你看到它可以动态注册BeanDefinition时有什么想法,对,你想的没错,注解开发原理中就是用Spring的后置处理器来动态创建Bean对象的,别眨眼,接下来就时见证奇迹的时刻


Bean工厂后置处理器

Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;也就是当把xml中所有bean配置信息封装成BeanDefinition对象,装到BeanDefinitionMap集合后,但还没有反射创建bean对象时,再往map中注册BeanDefinition对象,后续反射就会创建出新的xml中未定义的对象


Bean工厂后处理器 – BeanFactoryPostProcessor
BeanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,在BeanDefinitionMap填充完毕后,Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能。

所以它的使用分以下几步

  • 创建一个处理器类实现BeanFactoryPostProcessor接口
  • 重写BeanFactoryPostProcessor的方法
  • 交给Spring容器管理(配置到xml中或加注解)

使用方式如下

在这里插入图片描述


由于BeanDefinition是接口,我们要new 一个BeanDefinition对象,就要new 它的一个实现类RootBeanDefinition对象

在这里插入图片描述


其中需要强转为DefaultListableBeanFactory是因为,ConfigurableListableBeanFactory的对象无法把beanDefinition注册到map中,BeanDefinitionMap是DefaultListableBeanFactory中定义的集合,而DefaultListableBeanFactory又是实现了ConfigurableListableBeanFactory的接口,所以强转一下。

在这里插入图片描述

不得不说,这个源码自己也需要多看,不然这些接口名类名是什么,继承了什么,有什么关键成员变量都不清楚,看这些调用关系自然就云里雾里


Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作

public class MyBeanFactoryPostProcessor2 implements BeanDefinitionRegistryPostProcessor {
    
    
	//这个方法是BeanFactoryPostProcessor接口的方法,重写一下就不用管了
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    
    }

	
	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
    
    
			BeanDefinition beanDefinition = new RootBeanDefinition();
			beanDefinition.setBeanClassName("com.dao.UserDaoImpl");//要创建的bean的位置
			//注册beanDefinition
			beanDefinitionRegistry.registerBeanDefinition("userDao",beanDefinition);
		}
}

最后main方法中调用时

UserDao userDao = applicationContext.getBean(UserDao.class)

在这里插入图片描述


Bean后置处理器

Bean后处理器 – BeanPostProcessor

Bean被实例化后,到最终缓存到名为singletonObjects单例池之前,中间会经过Bean的初始化过程,例如:属性的填充、初始方法init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,我们称为Bean后处理。跟上面的Bean工厂后处理器相似,它也是一个接口,实现了该接口并被容器管理的BeanPostProcessor,会在流程节点上被Spring自动调用。


bean后处理器的使用步骤和bean工厂后处理器基本类似,只是处理时机不一样,bean工厂后处理器在填充map后,实例化前;bean后处理器在实例化后,添加单例池前

  • 创建后处理器类(自己随便创建一个就行)
  • 实现 BeanPostProcessor接口,重写它的方法
  • 把后处理器类交由bean管理

BeanPostProcessor的接口定义如下(模板):

public interface BeanPostProcessor {
    
    
	@Nullable//表示该方法可以不写
	//在属性注入完毕,init初始化方法执行之前被回调
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
		return bean;
	}
	@Nullable
	//在初始化方法执行之后,被添加到单例池singletonObjects之前被回调
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
		return bean;
	}
}

在这里插入图片描述


自定义@Component实现注解开发

  • 自定义@MyComponent注解,使用在类上;
  • 使用包扫描器工具BaseClassScanUtils 完成指定包的类扫描;
  • 自定义BeanFactoryPostProcessor完成注解@MyComponent的解析,解析后最终被Spring管理。(注意实现BeanFactoryPostProcessor接口的类需要交由Spring管理)

原理大概就是用包扫描工具类,指定包及其子包下的类上加了自定义注解的类名获取并添加到一个map集合中,然后遍历依次对它们进行包装成一个个BeanDefinition对象,然后再它们注册到BeanDefinitionMap集合中,后续反射创建bean时,这些注解添加的bean也会被创建。

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
    
		//指定要扫描的包
        String basePackage = "com";
		//调用扫描工具BaseClassScanUtils扫描指定包及其子包下的@MyComponent
        Map<String, Class> myComponentClassMap = BaseClassScanUtils.scanMyComponentAnnotation(basePackage);
		//遍历Map集合,创建BeanDefinition对象进行注册
        myComponentClassMap.forEach((beanName,clazz)->{
    
    
            try {
    
    
                BeanDefinition beanDefinition = new RootBeanDefinition();
                beanDefinition.setBeanClassName(clazz.getName());
                registry.registerBeanDefinition(beanName,beanDefinition);
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        });}

不得不说有那味了

猜你喜欢

转载自blog.csdn.net/giveupgivedown/article/details/129129640