zoukankan      html  css  js  c++  java
  • Spring框架参考手册(4.2.6版本)翻译——第三部分 核心技术 6.8 容器扩展点 6.8.1 使用BeanPostProcessor定制Bean

    6.8 容器扩展点

    通常,应用程序开发人员不需要实现ApplicationContext子类。反而,可以通过专门的集成接口的实现以插件形式来扩展Spring IoC容器。接下来的几节将介绍这些集成接口。

    6.8.1 使用BeanPostProcessor定制Bean

    BeanPostProcessor接口定义了回调方法,通过实现它来提供您自己的(或覆盖容器的默认)实例化逻辑,依赖关系解析逻辑等。如果要在Spring容器完成实例化,配置和初始化bean之后实现某些自定义逻辑,则能够以插件方式集成一个或多个BeanPostProcessor的实现。

    您可以配置多个BeanPostProcessor实例,并且可以通过设置order属性来控制这些BeanPostProcessors的执行顺序。仅当BeanPostProcessor实现Ordered接口时,才能设置此属性; 如果你编写自己的BeanPostProcessor,你也应该考虑实现Ordered接口。有关更多详细信息,请参阅BeanPostProcessor和Ordered接口的javadoc。另请参阅以下有关BeanPostProcessors的程序化注册的说明。

    BeanPostProcessors在bean(或对象)实例上运行; 也就是说,Spring IoC容器实例化一个bean实例,然后BeanPostProcessors就执行它们的工作。
    BeanPostProcessors的作用域是每个容器。这仅在您使用容器层级时才有意义。如果在一个容器中定义BeanPostProcessor,它将只对该容器中的bean进行后置处理。 换句话说,在一个容器中定义的bean不会被另一个容器中定义的BeanPostProcessor进行后置处理,即使两个容器都是同一层级的一部分。
    要变更实际的bean定义(即定义bean的蓝图),您需要使用BeanFactoryPostProcessor,如第6.8.2节“使用BeanFactoryPostProcessor定制配置元数据”中所述。

    org.springframework.beans.factory.config.BeanPostProcessor接口由两个回调方法组成。 当这样的类被注册为容器的后置处理器时,对于容器创建的每个bean实例,在调用容器初始化方法(例如InitializingBean的afterPropertiesSet()以及声明的init方法)之前和在任何bean初始化回调之后,后处理器都可以从容器中获得回调。后处理器可以对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后处理器时,这是非常有用的。但请注意,以编程方式添加的BeanPostProcessors不遵循Ordered接口,在这里是说注册的顺序就是执行的顺序。另请注意,不管是否显式地声明了顺序,以编程方式注册的BeanPostProcessors始终在通过自动检测注册的BeanPostProcessors之前处理。

    实现BeanPostProcessor接口的类是特殊的,容器会对它们进行差异处理。直接引用的所有BeanPostProcessors和bean都会在启动时实例化,作为ApplicationContext的专有启动阶段的一部分。接下来,所有BeanPostProcessors都以排序方式注册,并应用于容器中的今后所有其他的bean。由于AOP自动代理是作为BeanPostProcessor本身实现的,所以BeanPostProcessors和它们直接引用的bean都不适合自动代理,因此将它们应用于切面。
    对于任何此类bean,您应该看到一条信息性日志消息:“Bean foo不适合所有BeanPostProcessor接口处理(例如:不符合自动代理条件)”。
    请注意,如果使用自动装配或@Resource将bean连接到BeanPostProcessor(可能会回退到自动装配),Spring可能会在搜索类型匹配依赖候选项时访问意外的bean,因而使它们不符合自动代理或其他bean后处理类型。例如,如果您有一个使用@Resource注解的依赖项,其中field / setter名称不直接对应于bean的声明名称而且没有使用name属性,那么Spring就会通过类型匹配来访问其他bean。

    以下示例显示如何在ApplicationContext中编写,注册和使用BeanPostProcessors。

    示例:Hello World,BeanPostProcessor样式

    第一个例子说明了基本用法。该示例显示了一个自定义BeanPostProcessor实现,该实现在容器创建时调用每个bean的toString()方法,并将生成的字符串输出到系统控制台。

    在下面找到自定义BeanPostProcessor实现类定义:

    package scripting;
    
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.beans.BeansException;
    
    public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
    
        // simply return the instantiated bean as-is
        public Object postProcessBeforeInitialization(Object bean,
                String beanName) throws BeansException {
            return bean; // we could potentially return any object reference here...
        }
    
        public Object postProcessAfterInitialization(Object bean,
                String beanName) throws BeansException {
            System.out.println("Bean ''" + beanName + "'' created : " + bean.toString());
            return bean;
        }
    
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:lang="http://www.springframework.org/schema/lang"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/lang
            http://www.springframework.org/schema/lang/spring-lang.xsd">
    
        <lang:groovy id="messenger"
                script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
            <lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
        </lang:groovy>
    
        <!--
        when the above bean (messenger) is instantiated, this custom
        BeanPostProcessor implementation will output the fact to the system console
        -->
        <bean class="scripting.InstantiationTracingBeanPostProcessor"/>
    
    </beans>

    请注意如何简化定义InstantiationTracingBeanPostProcessor。它甚至没有名称,因为它是一个bean,它可以像任何其他bean一样依赖注入。(前面的配置还定义了一个由Groovy脚本支持的bean。Spring动态语言支持在名为第34章,动态语言支持章节中有详细介绍。)
    以下是用于执行上述代码和配置的简单Java应用程序:

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.scripting.Messenger;
    
    public final class Boot {
    
        public static void main(final String[] args) throws Exception {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
            Messenger messenger = (Messenger) ctx.getBean("messenger");
            System.out.println(messenger);
        }
    
    }

    上述应用程序的输出类似于以下内容:

    Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
    org.springframework.scripting.groovy.GroovyMessenger@272961
    示例:RequiredAnnotationBeanPostProcessor

    将回调接口或注解与自定义BeanPostProcessor实现相结合的使用是扩展Spring IoC容器的常用方法。一个例子是Spring的RequiredAnnotationBeanPostProcessor——一个随Spring发行版一起提供的BeanPostProcessor实现,它确保用(任意)注解标记的bean上的JavaBean属性是真实的(配置为)依赖注入值。

  • 相关阅读:
    左右下划线,中间文字
    sql语言动词
    SQL语言的四个组成部分
    MySQL执行一条查询语句的内部执行过程
    07 | 行锁功过:怎么减少行锁对性能的影响?
    06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
    05 | 深入浅出索引(下)
    04 | 深入浅出索引(上)
    03 | 事务隔离:为什么你改了我还看不见?
    02 | 日志系统:一条SQL更新语句是如何执行的?
  • 原文地址:https://www.cnblogs.com/springmorning/p/10361660.html
Copyright © 2011-2022 走看看