SpringIOC-注册BeanPostProcessors
前言 invokeBeanFactoryPostProcessors 方法主要用于处理 BeanFactoryPostProcessor 接口,而 registerBeanPostProcessors 方法主要用于处理 BeanPostProcessor 接口。BeanFactoryPostProcessor 和 BeanPostProcessor,相信大家很容易从命名看出来这两个接口“长得很像”。BeanFactoryPostProcessor 是针对 BeanFactory 的扩展,主要用在 bean 实例化之前,读取 bean 的定义,并可以修改它。BeanPostProcessor 是针对 bean 的扩展,主要用在 bean 实例化之后,执行初始化方法前后,允许开发者对 bean 实例进行修改。
本方法会注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在 registerBeanPostProcessors 方法只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,在执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。
registerBeanPostProcessors
入口方法是registerBeanPostProcessors,主要完成BeanPostProcessors提前实例化以及注册
1 2 3 4 5 6 7 protected void registerBeanPostProcessors (ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this ); }
registerBeanPostProcessors
来到PostProcessorRegistrationDelegate类
把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 public static void registerBeanPostProcessors ( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true , false ); int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker (beanFactory, beanProcessorTargetCount)); List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList <>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList <>(); List<String> orderedPostProcessorNames = new ArrayList <>(); List<String> nonOrderedPostProcessorNames = new ArrayList <>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); List<BeanPostProcessor> orderedPostProcessors = new ArrayList <>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList <>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); beanFactory.addBeanPostProcessor(new ApplicationListenerDetector (applicationContext)); }
registerBeanPostProcessors 1 2 3 4 5 6 7 8 9 10 11 12 13 private static void registerBeanPostProcessors ( ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) { for (BeanPostProcessor postProcessor : postProcessors) { beanFactory.addBeanPostProcessor(postProcessor); } }
beanFactory.addBeanPostProcessor
将PostProcessor添加到BeanFactory中的beanPostProcessors缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public void addBeanPostProcessor (BeanPostProcessor beanPostProcessor) { Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null" ); this .beanPostProcessors.remove(beanPostProcessor); if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) { this .hasInstantiationAwareBeanPostProcessors = true ; } if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) { this .hasDestructionAwareBeanPostProcessors = true ; } this .beanPostProcessors.add(beanPostProcessor); }
该方法作用就是将 BeanPostProcessor 添加到 beanPostProcessors 缓存,这边的先移除再添加,主要是起一个排序的作用。而 hasInstantiationAwareBeanPostProcessors 和 hasDestructionAwareBeanPostProcessors 变量用于指示 beanFactory 是否已注册过 InstantiationAwareBeanPostProcessors 和 DestructionAwareBeanPostProcessor,在之后的 IoC 创建过程会用到这两个变量,这边先有个印象。
BeanPostProcessors接口
Spring提供了一个BeanPostProcessor接口,这个接口的作用在于对于新构造的实例可以做一些自定义的修改。比如如何构造、属性值的修改、构造器的选择。
如果想改变Spring容器中bean的一些属性或者行为,可以通过自定义类实现BeanPostProcessor接口实现。
BeanPostProcessor的定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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总结
postProcessBeforeInitialization方法的作用在于目标对象实例化之后,初始化之前调用,默认返回原始对象,也可以返回一个包装实例; 如果返回null,接下来的BeanPostProcessors都不会执行
postProcessAfterInitialization方法的作用在于目标对象实例化之后,初始化之后调用,默认返回原始对象,也可以返回一个包装实例; 如果返回null,接下来的BeanPostProcessors都不会执行
初始化(Initialization):表示生成对象,未设置属性;初始化之前表示bean的初始化回调之前,如InitializingBean接口的afterPropertiesSet方法或者自定义的init-method方法
常用的接口 InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor接口继承自BeanPostProcessor接口,定义了4个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { @Nullable default Object postProcessBeforeInstantiation (Class<?> beanClass, String beanName) throws BeansException { return null ; } default boolean postProcessAfterInstantiation (Object bean, String beanName) throws BeansException { return true ; } @Nullable default PropertyValues postProcessProperties (PropertyValues pvs, Object bean, String beanName) throws BeansException { return null ; } @Deprecated @Nullable default PropertyValues postProcessPropertyValues ( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { return pvs; } }
小结
postProcessBeforeInstantiation方法在目标对象实例化之前调用,可以返回一个代理对象来代替目标对象本身;如果返回非null对象,则除了调用postProcessAfterInitialization方法外,其他bean的构造过程都不再调用;
postProcessAfterInstantiation方法在对象实例化之后,属性设置之前调用;如果返回值是true,目标bean的属性会被populate,返回false则忽略populate过程;
postProcessPropertyValues方法在属性被设置到目标实例之前调用,可以修改属性的设置,PropertyValues pvs表示参数值,PropertyDescriptor[] pds表示目标bean 的属性描述信息,返回值PropertyValues,可以用一个全新的PropertyValues来替代原来的pvs,如果返回null,将忽略属性设置过程;
SmartInstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor接口继承InstantiationAwareBeanPostProcessor接口,定义了3个方法,作用是在于目标对象的实例化过程中需要处理的事情。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor { @Nullable default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException { return null ; } @Nullable default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { return null ; } default Object getEarlyBeanReference (Object bean, String beanName) throws BeansException { return bean; } }
小结
predictBeanType方法预测Bean的类型,返回预测成功的Class类型,默认或如果不能预测返回null
determineCandidateConstructors方法用于选择合适的构造器,如果类有多个构造器,可以实现这个方法选择合适的构造器并用于实例化对象;该方法在postProcessBeforeInstantiation方法和postProcessAfterInstantiation方法之间调用,如果postProcessBeforeInstantiation方法返回了一个新的实例代替了原本该生成的实例,那么该方法会被忽略;
getEarlyBeanReference方法用于解决循环引用 问题。比如ReferenceA实例内部有ReferenceB的引用,ReferenceB实例内部有ReferenceA的引用。首先先实例化ReferenceA,实例化完成之后提前把这个bean暴露在ObjectFactory中,然后populate属性,这个时候发现需要ReferenceB。然后去实例化ReferenceB,在实例化ReferenceB的时候它需要ReferenceA的实例才能继续,这个时候就会去ObjectFactory中找出了ReferenceA实例,ReferenceB顺利实例化。ReferenceB实例化之后,ReferenceA的populate属性过程也成功完成,注入了ReferenceB实例。提前把这个bean暴露在ObjectFactory中,这个ObjectFactory获取的实例就是通过getEarlyBeanReference方法得到的;
DestructionAwareBeanPostProcessor 1 2 3 4 5 6 7 8 9 10 public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor { void postProcessBeforeDestruction (Object bean, String beanName) throws BeansException; default boolean requiresDestruction (Object bean) { return true ; } }
小结
postProcessBeforeDestruction方法在目标bean被销毁之前调用,该回调适用于单例bean的使用;
判断目标bean是否需要回调postProcessBeforeDestruction方法;
总结 Spring内部对象bean的生命周期管理有一套完成的体系,并遵循了设计模式中的开闭原则(开放扩展,关闭修改),如果想修改bean的相关信息,可以通过Spring提供的扩展点,如BeanPostProcessor接口去处理,这样做的好处是不需要关心Spring内部处理逻辑,扩展方便。
BeanPostProcessor扩展 自定义实现 创建BeanPostProcessor的实现类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Component public class CustomBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { System.out.println("bean实例化完成:" + beanName); if (bean instanceof UserDao) { UserDao userDao = (UserDao) bean; userDao.setPingSql("postProcessAfterInitialization" ); } return bean; } @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { System.out.println("开始实例化:" + beanName); if (bean instanceof UserDao) { UserDao userDao = (UserDao) bean; userDao.setPingSql("postProcessBeforeInitialization" ); } return bean; } }
测试类 1 2 3 4 5 6 7 8 9 10 public class SpringTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("Spring.xml" ); System.out.println("开始调用getBean" ); UserDao userDao = (UserDao) context.getBean("userDao" ); System.out.println(userDao); } }
打印信息 1 2 3 4 开始实例化:userDao bean实例化完成:userDao 开始调用getBean UserDao{dialect='MYSQL' , pingSql='yyyyyyyyyyyyy' }