Spring之BeanDefinitionRegistryPostProcessor类详解

Posted 敲代码的小小酥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之BeanDefinitionRegistryPostProcessor类详解相关的知识,希望对你有一定的参考价值。

一、BeanDefinitionRegistryPostProcessor类

/*
 * Copyright 2002-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;

/**
 * Extension to the standard {@link BeanFactoryPostProcessor} SPI, allowing for
 * the registration of further bean definitions <i>before</i> regular
 * BeanFactoryPostProcessor detection kicks in. In particular,
 * BeanDefinitionRegistryPostProcessor may register further bean definitions
 * which in turn define BeanFactoryPostProcessor instances.
 *
 * @author Juergen Hoeller
 * @since 3.0.1
 * @see org.springframework.context.annotation.ConfigurationClassPostProcessor
 */
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

下面我们翻译其注释。

Extension to the standard BeanFactoryPostProcessor SPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in. In particular, BeanDefinitionRegistryPostProcessor may register further bean definitions which in turn define BeanFactoryPostProcessor instances.

对标准beanfactorypostprocessor的扩展,允许在常规BeanFactoryPostProcessor检测开始之前注册更多的bean定义。特别地,BeanDefinitionRegistryPostProcessor可以注册更多的bean定义,这些定义反过来定义BeanFactoryPostProcessor实例。

由源码我们可以看到BeanDefinitionRegistryPostProcessor继承了beanfactorypostprocessor类,是对其的扩展。beanfactorypostprocessor类我们稍后讲解。

下面我们看接口定义的方法:

Modify the application context’s internal bean definition registry after its standard initialization. All regular bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for adding further bean definitions before the next post-processing phase kicks in.
Params:
registry – the bean definition registry used by the application context
在标准初始化之后修改应用程序上下文的内部bean定义注册表。所有常规bean定义都将被加载,但是还没有bean被实例化。这允许在下一个后期处理阶段开始之前添加更多bean定义。

这里做一下说明:标准化的初始化理解为spring解析xml和scan的类,形成BeanDefiniton对象,并进行注册到BeanFactory后。
这个接口的执行触发时机是BeanDefinition注册到BeanFactory,实例化之前执行的。

void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

方法的参数是BeanDefinitionRegistry ,前面我们讲到,BeanDefinitionRegistry是将BeanDefinition注册到BeanFactory的作用。这就说明,是在注册之前,调用此方法,对注册器中的BenDefiniton对象进行增删改查的操作。

我们要对BeanDefiniton进行增删改查,需要自定义类,实现BeanDefinitionRegistryPostProcessor接口,然后实现方法进行BeanDefiniton的增删改查。

实现BeanDefinitionRegistryPostProcessor接口的类,需要用@Component修饰,加入到spring容器中,才会被spring所解析。上面我们提到,执行该接口的方式,是在实例化对象之前。但是要执行这个接口实现类的方法,就必须得实例化这个接口的实现类。所以,BeanDefinitionRegistryPostProcessor实现类的实例化过程,是在执行postProcessBeanDefinitionRegistry方法之前实例化的,这个实现类的实例化是最早进行的。

postProcessBeanDefinitionRegistry方法的参数BeanDefinitionRegistry,是spring在初始化过程中,自己传入进去的,我们无需管这个对象是哪里来的,在方法里直接使用即可。这个原理我们一定要搞懂,实现某些接口时,接口参数为我们提供了一些框架自身级别的类作为参数让我们调用,那这个参数一定是框架在运行过程中自己维护的一个对象,我们只要取对象中的属性来应用即可。

二、BeanFactoryPostProcessor类

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

/**
 * Factory hook that allows for custom modification of an application context's
 * bean definitions, adapting the bean property values of the context's underlying
 * bean factory.
 *
 * <p>Useful for custom config files targeted at system administrators that
 * override bean properties configured in the application context. See
 * {@link PropertyResourceConfigurer} and its concrete implementations for
 * out-of-the-box solutions that address such configuration needs.
 *
 * <p>A {@code BeanFactoryPostProcessor} may interact with and modify bean
 * definitions, but never bean instances. Doing so may cause premature bean
 * instantiation, violating the container and causing unintended side-effects.
 * If bean instance interaction is required, consider implementing
 * {@link BeanPostProcessor} instead.
 *
 * <h3>Registration</h3>
 * <p>An {@code ApplicationContext} auto-detects {@code BeanFactoryPostProcessor}
 * beans in its bean definitions and applies them before any other beans get created.
 * A {@code BeanFactoryPostProcessor} may also be registered programmatically
 * with a {@code ConfigurableApplicationContext}.
 *
 * <h3>Ordering</h3>
 * <p>{@code BeanFactoryPostProcessor} beans that are autodetected in an
 * {@code ApplicationContext} will be ordered according to
 * {@link org.springframework.core.PriorityOrdered} and
 * {@link org.springframework.core.Ordered} semantics. In contrast,
 * {@code BeanFactoryPostProcessor} beans that are registered programmatically
 * with a {@code ConfigurableApplicationContext} will be applied in the order of
 * registration; any ordering semantics expressed through implementing the
 * {@code PriorityOrdered} or {@code Ordered} interface will be ignored for
 * programmatically registered post-processors. Furthermore, the
 * {@link org.springframework.core.annotation.Order @Order} annotation is not
 * taken into account for {@code BeanFactoryPostProcessor} beans.
 *
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @since 06.07.2003
 * @see BeanPostProcessor
 * @see PropertyResourceConfigurer
 */
@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;

}

翻译其注释:

Factory hook that allows for custom modification of an application context’s bean definitions, adapting the bean property values of the context’s underlying bean factory.
工厂钩子,允许客户端对spring初始化好的beandefinition对象进行修改,调整bean的属性值。

Useful for custom config files targeted at system administrators that override bean properties configured in the application context. See PropertyResourceConfigurer and its concrete implementations for out-of-the-box solutions that address such configuration needs.
对于覆盖在应用程序上下文中配置的bean属性的针对系统管理员的自定义配置文件非常有用。请参阅PropertyResourceConfigurer及其具体实现,以获取满足此类配置需求的现成解决方案。

一会对PropertyResourceConfigurer进行查看。继续看其注解:

A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. If bean instance interaction is required, consider implementing BeanPostProcessor instead.
BeanFactoryPostProcessor可以与beandefinition进行交互和修改,但不能与bean实例进行交互。这样做可能会导致bean过早实例化,违反容器并导致意外的副作用。如果需要bean实例交互,请考虑实现BeaPASTePrimor。

这句话的意思是BeanFactoryPostProcessor接口可以修改BeanDefinition对象,而不是bean的实例。如果想与bean的实例进行交互,用BeaPASTePrimor。BeaPASTePrimor是什么我们后面说,继续读注释:

An ApplicationContext auto-detects BeanFactoryPostProcessor beans in its bean definitions and applies them before any other beans get created. A BeanFactoryPostProcessor may also be registered programmatically with a ConfigurableApplicationContext.
ApplicationContext自动在其beandefinition中检测BeanFactoryPostProcessor bean,并在创建任何其他bean之前应用它们。BeanFactoryPostProcessor也可以用ConfigurableApplicationContext以编程方式注册。

如何用ConfigurableApplicationContext方式注册,我们下面再讲,继续看注释:

BeanFactoryPostProcessor beans that are autodetected in an ApplicationContext will be ordered according to org.springframework.core.PriorityOrdered and org.springframework.core.Ordered semantics. In contrast, BeanFactoryPostProcessor beans that are registered programmatically with a ConfigurableApplicationContext will be applied in the order of registration; any ordering semantics expressed through implementing the PriorityOrdered or Ordered interface will be ignored for programmatically registered post-processors. Furthermore, the @Order annotation is not taken into account for BeanFactoryPostProcessor beans.
在应用程序上下文中自动检测到的BeanFactoryPostProcessor bean将根据org.springframework.core.PriorityOrdered和org.springframework.core.ordered语义进行排序。相反,用ConfigurableApplicationContext编程注册的BeanFactoryPostProcessorbean将按注册顺序应用;对于以编程方式注册的后处理器,通过实现PriorityOrdered或Ordered接口表达的任何排序语义都将被忽略。此外,beanfactorypostprocessorbean不考虑@Order注释。

下面看接口方法及注释:

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.
在标准初始化之后修改应用程序上下文的内部bean工厂。所有bean定义都将被加载,但是还没有bean被实例化。这允许重写或添加属性,即使是对bean。

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

可以看出,方法的参数是ConfigurableListableBeanFactory,是对beanFactory中的BeanDefinition熟悉做的修改。

现在,我们比较一下BeanFactoryPostProcessor接口和BeanDefinitionRegistryPostProcessor接口。BeanFactoryPostProcessor方法中参数是ConfigurableListableBeanFactory,我们看这个对象有哪些方法:
在这里插入图片描述
可以看到,这个方法主要是获得BeanDefiniton对象,然后修改BeanDefiniton的属性值。
BeanDefinitionRegistryPostProcessor接口的方法参数是BeanDefinitionRegistry对象,其方法包括;
在这里插入图片描述
可以看出,该方法主要是增加或移除BeanDefinition,也可以获得BeanDefiniton,对其属性进行修改。所以该方法主要是对BeanDefiniton的增删改查。其实在一定程度上,BeanDefinitionRegistryPostProcessor的功能包含了其父接口BeanFactoryPostProcessor的功能。

两个接口方法的执行顺序是先执行BeanDefinitionRegistryPostProcessor,再执行BeanFactoryPostProcessor。由参数类型我们也可以知道,肯定是先执行注册BeanDefinition,然后等BeanDefinition注册到BeanFactory后,再操作beanFactory。

以上是关于Spring之BeanDefinitionRegistryPostProcessor类详解的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码窥探之:Spring IOC之@Value

风暴之Spring事务

我们一起学习Spring之Spring简介

Spring系列之手写一个SpringMVC

一文彻底解密Spring 源码之Spring MVC

java之spring之helloword