https://blog.csdn.net/panghuangang/article/details/136307004
https://docs.spring.io/spring-framework/reference/core/beans/factory-extension.html
通常,应用程序开发人员不需要对ApplicationContext
实现类进行子类化。相反,可以通过插入特殊集成接口的实现来扩展Spring IoC容器。
BeanPostProcessor
接口定义了回调方法,你可以实现这些方法来提供自己的(或覆盖容器的默认)实例化逻辑、依赖解析逻辑等等。如果你想在Spring容器完成bean的实例化、配置和初始化后执行一些自定义逻辑,你可以插入一个或多个自定义的BeanPostProcessor
实现。
你可以配置多个BeanPostProcessor
实例,并且可以通过设置order
属性来控制这些BeanPostProcessor
实例的运行顺序。只有当BeanPostProcessor
实现了Ordered
接口时,你才能设置这个属性。如果你编写自己的BeanPostProcessor
,也应该考虑实现Ordered
接口。
BeanPostProcessor
实例操作bean(或对象)实例。也就是说,Spring IoC容器实例化一个bean实例,然后BeanPostProcessor
实例执行它们的工作。
BeanPostProcessor
实例是每个容器范围内的。这只在使用容器层次结构时才相关。如果你在一个容器中定义了一个BeanPostProcessor
,它只会后处理那个容器中的bean。换句话说,即使在相同的层次结构中,一个容器中定义的bean也不会被另一个容器中定义的BeanPostProcessor
后处理。
要更改实际的bean定义(即定义bean的模板),你需要使用BeanFactoryPostProcessor
。
org.springframework.beans.factory.config.BeanPostProcessor
接口正好包含两个回调方法。当这样一个类作为后处理器在容器中注册时,对于容器创建的每一个bean实例,后处理器都会在容器初始化方法(如InitializingBean.afterPropertiesSet()
或任何声明的init
方法)被调用之前和之后从容器获得回调。后处理器可以对bean实例采取任何操作,包括完全忽略回调。一个bean后处理器通常会检查回调接口,或者它可能会用代理包装一个bean。一些Spring AOP基础设施类就是作为bean后处理器实现的,以便提供代理包装逻辑。
ApplicationContext
会自动检测配置元数据中定义的任何实现了BeanPostProcessor
接口的bean。ApplicationContext
将这些bean注册为后处理器,以便稍后在创建bean时调用它们。bean后处理器可以像其它任何bean一样部署在容器中。
当在配置类上使用@Bean
工厂方法声明一个BeanPostProcessor
时,工厂方法的返回类型应该是实现类本身或至少是org.springframework.beans.factory.config.BeanPostProcessor
接口,明确指示该bean的后处理器性质。否则,ApplicationContext
在完全创建它之前无法通过类型自动检测到它。由于BeanPostProcessor
需要在其它上下文中的bean初始化之前实例化,因此这种早期的类型检测至关重要。
尽管推荐的BeanPostProcessor
注册方法是通过ApplicationContext
自动检测(如前所述),但你也可以通过使用addBeanPostProcessor
方法在ConfigurableBeanFactory
上以编程方式注册它们。当你需要在注册之前评估条件逻辑,或者甚至在层次结构中的上下文之间复制bean后处理器时,这可能会很有用。然而,请注意,以编程方式添加的BeanPostProcessor
实例不会遵循Ordered
接口指定的顺序。在这里,执行的顺序由注册的顺序决定。还要注意的是,无论是否有任何显式排序,以编程方式注册的BeanPostProcessor
实例总是会在通过自动检测注册的实例之前处理。
实现BeanPostProcessor
接口的类是特殊的,并且会被容器以不同的方式处理。所有的BeanPostProcessor
实例及其直接引用的bean都会在启动时实例化,作为ApplicationContext
特殊启动阶段的一部分。接下来,所有的BeanPostProcessor
实例会以排序的方式注册,并应用到容器中所有后续的bean。因为AOP自动代理是通过BeanPostProcessor
本身实现的,所以BeanPostProcessor
实例及其直接引用的bean都不适合自动代理,因此不会有切面编织到它们中。
对于任何这样的bean,你应该会看到一条信息性日志消息:Bean someBean
不符合由所有BeanPostProcessor
接口处理的资格(例如:不符合自动代理的资格)。
如果你使用自动装配或@Resource
(可能会回退到自动装配)将bean注入到你的BeanPostProcessor
中,Spring在搜索类型匹配的依赖候选时可能会访问到意外的bean,因此,使它们不符合自动代理或其它类型的bean后处理的资格。例如,如果你有一个用@Resource
注解的依赖,其中字段或setter的名称与bean的声明名称不直接对应,且没有使用name属性,Spring会通过类型匹配来访问其它bean。
以下示例展示了如何在ApplicationContext
中编写、注册和使用BeanPostProcessor
实例。
这个例子展示了基本的用法。示例中展示了一个自定义的BeanPostProcessor
实现,它在容器创建每个bean时调用其toString()
方法,并将结果字符串打印到系统控制台。