一般来说,一个应用开发者不需要继承ApplicationContext实现类。取而代之的是,Spring IoC容器可以通过插入特殊的整合接口的实现来进行扩展。下面的几点将要讲述这些整合的接口。

1.使用BeanPostProcessor来定制bean

BeanPostProcessor接口定义了你可以实现的回调方法去提供自己的实例化逻辑、依赖方案逻辑等等。如果你想在Spring 容器完成实例化配置和初始化一个bean之后实现一个自定义逻辑,你可以插入一个或者多个BeanPostProcessor实现。

你可以配置多个BeanPostProcessor实例,你可以通过设置order属性来控制这些BeanPostProcessor运行的顺序。如果你写自己的BeanPostProcessor你应该考虑实现ordered接口。

注意:BeanPostProcessors作用在一个bean实例上,也就是说,Spring IOC容器实例化一个bean实例然后BeanPostProcessors会在他们上面起作用。BeanPostProcessor在每一个容器中都是受限制域的。如果你使用容器分层结构的话这个是唯一有关系的。如果你在一个容器中定义一个BeanPostProcessor接口,它将知识处理在容器中的bean。换句话说,在一个容器中定义的bean并不能被定义在其他容器中的BeanPostProcessor来处理,即使两个容器时同一个层次的一部分。为了改变实际的bean定义,你需要使用一个BeanFactoryPostProcessor。

org.springframework.beans.factory.config.BeanPostProcessor 由两个回调方法组成。当这样的类在容器中被注册为一个post-processor时,对于任何一个在容器中创建的bean实例,post-processor从容器中获得一个回调,在容器初始化方面之前的两个方法(afterPropertiesSet和init)也被称为在任何bean初始化回调。post-processor能够对任何一个实例进行操作,包括完全忽略回调。一个bean post-processor一般会将会检查回调接口或者是用一个代理来封装bean。为了提供一个代理封装逻辑一些Spring AOP框架类作为bean post-processor来实现。

一个ApplicationContext能够发现实现了BeanPostProcessor接口的定义在配置中的任何bean。ApplicationContext注册这些bean作为post-processor以便他们在bean创建后可以被调用。bean post-processor就像其他bean一样被部署在容器中。

注意当在一个配置类中使用@Bean工厂方法声明一个BeanPostProcessor的时候,工厂方法的返回类型应该实现类自己或者至少是org.springframework.beans.factory.cofig.BeanPostProcessor接口,明确的表明了那个bean的是post-processor。否则,ApplicationContext在完全创建它之前不会通过类型自动发现它,因为为了在上下文中引用到其他bean的初始化一个BeanPostProcessor需要去实例化早些,而且这个早一点的声明是很关键的。

下面就是表明在一个ApplicationContext中定义注册和使用BeanPostProcessors.

1.1例子:Hello world,BeanPostProcessor风格的

第一个例子只是简单地使用。这个例子表明一个自定义的BeanPostProcessor实现当它被容器创建的时候调用了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一样DI。

下面的简单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

1.2 例子:RequiredAnnotationBeanPostProcessor

使用回调接口或者注解和一个自定义的BeanPostProcessor实现联合在一起是常用的方法用来扩展Spring Ioc容器。这个例子是Spring的conjunction-一个BeanPostProcessor实现,它可以保证在bean中JavaBean属性被标记注解的能够用一个值来进行依赖注入。

2.使用BeanFactoryPostProcessor来自定义配置数据

下面我们来看下org.springframework.beans.factory.config.BeanFactoryPostProcessor。这个接口的语法和那些BeanPostProcessor类似,有一点不同是:BeanFactoryPostProcessor作用在bean配置数据上;也就是说SpringIOC容器运行一个BeanFactoryPostProcessor去读取配置数据并且在实例化任何不适BeanFactoryPostProcessor的bean之前修改它的配置。

你可以配置多个BeanFactoryPostProcessors,而且你通过设置orde的顺序来控制BeanFactoryPostProcessors运行的顺序。但是,如果BeanFactoryPostProcessors实现了ordered接口你才能看到这个属性。你可以写自己的BeanFactoryPostProcessors,你应该考虑实现ordered接口。

一个bean工厂post-processor会被自动运行当在一个ApplicationContext内部声明的时候,这样做是为了将改变应用到定义容器的配置数据中。SPring包括很多提前定义好的bean 工厂 post-processors,比如PropertyOverrideConfigurer和PropertyPlaceholderConfigurer。一个自定义的BeanFactoryPostProcessor也是能够被使用的,例如为了注册定义的的属性编辑器。

一个ApplicationContext能够自动发现实现了BeanFactoryPostProcessor接口的部署在它里面的任何bean。它使用这些bean作为bean 工厂 post-processor在适当的时机。你可以

2.1例子:类名称代替PropertyPlaceholderConfigurer

你能够从使用标准Java 属性格式的定义在其他文件中的bean定义中使用PropertyPlaceholderConfigurer去具体化属性值。这样做,可以使用户在部署应用的时候自定义环境变量的属性,比如数据库url 和密码,而不用修改XML定义的文件。

看下面的基于XML格式配置的片段,这里面DataSource使用placeholder值来定义的。这个例子表明从外部属性文件中配置的属性使用。在运行的时候,一个PropertyPlaceholderConfigurer被应用在将替换数据源属性的元数据。需要替换的值需要被指明是placeholders的格式${property-name},这个和Ant / log4j / JSP EL 风格类似。

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

在其他文件中标准Java属性格式的实际值:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

因此,字符串 ${jdbc.username}在运行时被替换成值sa,这个也会应用在属性文件中其他的匹配的值上。PropertyPlaceholderConfigurer在大部分的属性和bean定义的 属性中会检查placeholders的。更多的话placeholders的前缀和后缀也能够被自定义。

在Spring 2.5中被引用的context 命名空间,这样可以使用指定的配置元素来定义属性placeholders。一个多个位置可以用逗号分隔成一个列表的位置属性。

<context:property-placeholder location="classpath:com/foo/jdbc.properties"/>

PropertyPlaceholderConfigurer不仅仅寻找你知道的属性文件中的属性。默认情况下,它还好检查Java系统属性如果在指定的属性文件中找不到的属性的话。你可以通过设置配置器的systemPropertiesMode为下面三个之一支持的属性整数值:

  • never(0):永远不要检查系统属性

  • fallback(1):如果在指定的属性文件中没有可供解析的话检查系统属性值。这个是默认选项。

  • override(2):在你查询指定的属性文件之前首先查询系统属性。这样运行系统属性能够覆盖任何其他的属性源。

    注意:你可以使用PropertyPlaceholderConfigurer来代替类名,这个在你必须取一个特别的实现类时是很有用的。例如:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
    <value>classpath:com/foo/strategy.properties</value>
    </property>
    <property name="properties">
    <value>custom.strategy.class=com.foo.DefaultStrategy</v alue>
    </property>
    </bean>
    <bean id="serviceStrategy" class="${custom.strategy.class}"/>

    如果在运行时类不能够解析为一个合法的类,当它将要被创建时bean的解析就会失败,这个是在一个非懒加载bean的在一个ApplicationContext的preInstantiateSingletons()的相位之间。

2.2例子:PropertyOverrideConfigurer

PropertyOverrideConfigurer,另外的bean 工厂 post-processor,和PropertyPaceholderConfigurer类似,但是又不像,因为原始的定义有默认值或者对于bean属性没有值。如果一个覆盖的Properties文件对于特定的bean属性没有输入值的话,缺省的上下文定义就会被使用了。

注意Bean定义不知道被覆盖了,所以在覆盖的配置在被使用的时候,XML定义的文件不是立即就知道的。在有多个PropertyOverrideConfigurer实例的清下中,可以为同一个bean属性值定义不同的值,最后一个起作用,这个取决于覆盖机制。

属性文件配置像下面的格式:

beanName.property=value

例如:

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb

这个例子在一个包含一个叫做数据源的bean的容器定义中使用,数据源包括驱动和url属性。

混合属性名字也是支持的,只要每一个路径中的组件希望的最后的属性被覆盖的不是非空。这个例子有:

foo.fred.bob.sammy=123

foo bean的fred属性的 bob属性的 sammy属性值是123。

使用Spring 2.5中的context命名空间,可以去配置属性覆盖通过一个致命的配置元素:

<context:property-override location="classpath:override.properties"/>

3.使用一个工厂bean来定制实例化逻辑

实现了org.springframework.beans.factory.FactoryBean接口的对象都是他们自己的工厂。

FactoryBean接口可以插入到Sring IOC 容器实例化逻辑的一个点。如果你有复杂的处理话代码,那么最好在Java代码中表示出来不要使用大量冗杂的XML,你可以创建自己的FactoryBean,写类内部写负责的初始化,然后将自己定制的FactoryBean放入容器中。

FactoryBean接口提供了三个方法:

  • Object getObject() : 返回这个工厂茶UN该敬爱年的 对象实例。这个实例能够被共享,这个取决于工厂返回的是单例还是原型。
  • boolean isSingleton() :如果FactoryBean返回单例就是返回true否则就是false;
  • Class getObjectType() : 返回通过getObject() 方法返回的对象类型,如果类型是未知的那么会返回null.

FactoryBeande 的接口在Spring框架中的很多地方都用到了,Spring自己有查过50个FactoryBean的接口实现。

当你需要去向容器请求一个它自己的真正的FactoryBean实例而不是它产生的bean,在bean的 id前面加上&在调用ApplicationContext的getBean()方法时,加入现在给定一个FactoryBean的id是myBean,调用getBean("myBean")将返回FactoryBean的产生的对象;但是调用getBean("&myBean")将会返回FactoryBean自己的实例

Spring IOC之容器扩展点的更多相关文章

  1. [转]Spring IOC父子容器简介

    通过HierarchicalBeanFactory接口,Spring的IoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,但父容器不能访问子容器的Bean.在容器内,Bean的 ...

  2. Spring IOC之容器概述

    1.SpringIOC容器和beans介绍 IOC的依赖注入是这样的,对象定义他们的依赖也就是他们需要在一起起作用的对象是通过构造器参数以及工厂方法的参数或者是当他们被构建或者是从工厂中返回时设置在对 ...

  3. Spring IOC 低级容器解析

    1.IOC是什么 IOC-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不 ...

  4. Spring IOC 一——容器装配Bean的简单使用

    下文:SpringIOC 二-- 容器 和 Bean的深入理解 写在前面 这篇文章去年写的,缘起于去年某段时间被领导临时"抓壮丁"般的叫过去做java开发,然后在网上找了一个 Sp ...

  5. Spring IOC 相关的面试题

    Spring最基础的部分就是IOC,对IOC的理解程度从某个方面代表着你对Spring  的理解程度,看了网上的一些面试题,针对Spring IOC相关的重点是下面几个: 1.Spring中Bean ...

  6. Spring-IOC 扩展点 BeanFactoryPostProcessor及其子接口解析

    BeanFactoryPostProcessor 接口的英文描述: Allows for custom modification of an application context's bean de ...

  7. Spring IOC 容器源码分析系列文章导读

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

  8. Spring源码系列 — BeanDefinition扩展点

    前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...

  9. Spring扩展点-v5.3.9

    Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework T ...

随机推荐

  1. 24L01/SI24R1调试笔记

    1.SPI MSB优先,8Bit寄存器地址与内容: 2.寄存器结构与之前使用的LT8900不同,分为R.W寄存器与特殊功能寄存器: 3.特别注意:在TX.RX.RT中断或者轮询后置1,必须写1清零与清 ...

  2. linux的自动化操作相关使用方法汇总(转)

    linux系统的web网站在运营状态时,我们常需要对网站进行维护,例如查看资源剩余并做出响应.日志分割.数据整理,在特定状态执行特定任务等等,这些都会需要linux能实现自动执行某些任任务.本篇博文介 ...

  3. a^b%c 的三种形式

    求a^b%c,(1  <= a,b <= 2^62, 1 <= c <= 10^9) 最主要的高速幂 _LL mod_exp(_LL a, _LL b, int c) { _L ...

  4. python基础课程_学习笔记21:文件和材料

    文件和材料 打开文件 open功能是用来打开文件,语法例如,下面的: open([name[,mode[,buffering]]) open函数使用一个文件名称作为唯一的强制參数,然后返回一个文件对象 ...

  5. DevExpress XtraReports 入门三 创建 Master-Detail(主/从) 报表

    原文:DevExpress XtraReports 入门三 创建 Master-Detail(主/从) 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用 ...

  6. [Network]Introduction and Basic concepts

    [该系列是检讨计算机网络知识.因为现在你想申请出国.因此,在写这篇博客系列的大多数英语.虽然英语,但大多数就是我自己的感受和理解,供大家学习和讨论起来] 1 Network Edge The devi ...

  7. Ubuntu Server 14.04 LTS(64bit)已安装 weblogic Server 12c(12.1.3) Zip Distribution

    这里说的对Ubuntu Server 14.04 LTS(64bit)已安装weblogic Server 12c(12.1.3) Zip Distribution遇到的问题.至于Windows什么好 ...

  8. js 正则学习小记之匹配字符串

    原文:js 正则学习小记之匹配字符串 今天看了第5章几个例子,有点收获,记录下来当作回顾也当作分享. 关于匹配字符串问题,有很多种类型,今天讨论 js 代码里的字符串匹配.(因为我想学完之后写个语法高 ...

  9. C# ICSharpCode.SharpZipLib

    C# ICSharpCode.SharpZipLib.dll文件压缩和解压功能类整理,上传文件或下载文件很常用 工作中我们很多时候需要进行对文件进行压缩,比较通用的压缩的dll就是ICSharpCod ...

  10. crawler_爬虫分布式设计图收集_01