项目实训 13 学习Spring(7)

212 阅读8分钟

1.7:Bean定义继承:

Bean 定义可以包含许多配置信息,包括构造函数参数,属性值和特定于容器的信息。

子 bean 定义能从父定义继承配置数据。子定义可以覆盖某些值或根据需要添加其他值。

使用基于 XML 的配置元数据时,可以通过使用parent属性(将父 bean 指定为该属性的值)来指示子 bean 定义。

例:

image.png

如果未指定子 bean 的class定义,则使用父定义中的 class 类,但也可以覆盖它。在后一种情况下,子 bean 类必须与父类兼容(也就是说,它必须接受父类的属性值)。

子bean将从父bean继承范围,构造函数参数值,属性值和方法替代,并可以选择添加新值。指定的任何范围,初始化方法,destroy 方法或static工厂方法设置都会覆盖相应的父设置。

不会继承的有自动装配模式,依赖项检查,单例和惰性初始化。

前面的示例通过使用abstract属性将父 bean 定义显式标记为抽象。如果父定义未指定类,则需要将父 bean 定义显式标记为abstract。这时,父 bean 不能单独实例化,因为它是不完整的,并且还被明确标记为abstract。当定义为abstract时,它只能用作纯模板 bean 定义,用作子定义的父定义。

如果您有一个(父)bean 定义仅打算用作模板,并且此定义指定了一个类,则必须确保设置* abstract 属性为 true *,否则应用程序上下文将实际(尝试)预先实例化abstract bean。

1.8:集装箱延伸点(Container Extension Points):

扩展 Spring IoC 容器并不需要继承Application Context类,Spring定义了些接口。

1.8.1:使用BeanPostProcessor自定义Bean:

BeanPostProcessor接口定义了回调方法,您可以实现这些回调方法,以提供自己的(或覆盖容器的默认值)实例化逻辑,依赖项解析逻辑等。如果您想在 Spring 容器完成实例化,配置和初始化 bean 之后实现一些自定义逻辑,则可以插入一个或多个BeanPostProcessor实现。

您可以配置多个BeanPostProcessor实例,并且可以通过设置order属性来控制这些BeanPostProcessor实例的执行序列。仅当BeanPostProcessor实现Ordered接口时,才可以设置此属性。如果您编写自己的BeanPostProcessor,则也应该考虑实现Ordered接口。

BeanPostProcessor bean实例按容器划分范围。如果在一个容器中定义BeanPostProcessor,则它将仅对该容器中的 bean 进行后处理。一个容器中定义的 Bean 不会被另一个容器中定义的BeanPostProcessor后处理。

当BeanPostProcessor接口被注册为容器的后处理器时,(Bean 后处理器可以以与其他任何 Bean 相同的方式部署在容器中。)对于容器创建的每个 bean 实例,后处理器都会在容器初始化方法(例如InitializingBean.afterPropertiesSet(),任何已声明的init之后)之前从容器获取回调方法,并在任何 bean 初始化回调之后调用。后处理器可以对 bean 实例执行任何操作,一些 Spring AOP 基础结构类被实现为 bean 后处理器,以提供代理包装逻辑。

注意,在配置类上使用@Bean工厂方法声明BeanPostProcessor时,工厂方法的返回类型应该是实现类本身或至少是org.springframework.beans.factory.config.BeanPostProcessor接口,从而清楚地表明该 bean 的后处理器性质。否则,ApplicationContext无法在完全创建之前按类型自动检测它。由于BeanPostProcessor需要提早实例化以便应用于上下文中其他 bean 的初始化,因此这种提早类型检测至关重要。

推荐的BeanPostProcessor注册方法是通过ApplicationContext自动检测(如前所述),但是您可以使用addBeanPostProcessor通过ConfigurableBeanFactory以编程方式注册它们。注意,以编程方式添加的BeanPostProcessor实例不遵守Ordered接口。在这里,注册的序列决定了执行序列。另请注意,以编程方式注册的BeanPostProcessor实例始终在通过自动检测注册的实例之前进行处理,而不考虑任何明确的序列。

实现BeanPostProcessor接口的类是特殊的,并且容器对它们的处理方式有所不同。BeanPostProcessor实例在启动时会实例化,作为ApplicationContext特殊启动阶段的一部分。接下来,以排序方式注册所有BeanPostProcessor实例,并将其应用于容器中的所有其他 bean。

由于 AOP 自动代理本身是由BeanPostProcessor实现的,因此BeanPostProcessor实例或它们直接引用的 bean 都不适合进行自动代理。

在Application Context中写入,注册和使用BeanPostProcessor的实例:
自定义BeanPostProcessor实现类的定义:(该示例显示了一个自定义BeanPostProcessor实现,该实现调用容器创建的每个 bean 的toString()方法,并将结果字符串打印到系统控制台。)

image.png

在XML中使用:

image.png

注意它没有名称,并且因为它是 Bean,所以可以像注入其他任何 Bean 一样对其进行依赖注入。

java应用程序运行:

image.png

输出为:

image.png

使用BeanFactoryPostProcessor自定义配置元数据:

org.springframework.beans.factory.config.BeanFactoryPostProcessor。此接口的语义与BeanPostProcessor相似,但有一个主要区别:BeanFactoryPostProcessor对 Bean 配置元数据进行操作。也就是说,Spring IoC 容器允许BeanFactoryPostProcessor读取配置元数据,并可能在容器实例化BeanFactoryPostProcessor实例以外的任何 bean 之前*对其进行更改。

您可以配置多个BeanFactoryPostProcessor实例,并且可以通过设置order属性来控制这些BeanFactoryPostProcessor实例的运行序列。但是,仅当BeanFactoryPostProcessor实现Ordered接口时才能设置此属性。如果您编写自己的BeanFactoryPostProcessor,则也应该考虑实现Ordered接口。

如果要更改实际的 bean 实例(即,已从配置元数据创建的对象),则需要使用BeanPostProcessor。尽管在技术上可以在BeanFactoryPostProcessor内使用 bean 实例(例如,通过使用BeanFactory.getBean()),但这样做会导致 bean 实例化过早,从而违反了标准容器的生命周期。这可能会导致负面影响,例如绕过 bean 后处理。

如果在一个容器中定义BeanFactoryPostProcessor,则仅将其应用于该容器中的 bean 定义。一个容器中的 Bean 定义不会由另一个容器中的BeanFactoryPostProcessor实例进行后处理,即使两个容器都属于同一层次结构也是如此。

通常不希望将BeanFactoryPostProcessor 配置为延迟初始化。因此,将其标记为延迟初始化将被忽略。

BeanFactoryPostProcessor起作用于其他bean初始化之前。

示例:类名替换PropertyPlaceholderConfigurer:

您可以使用标准 Java Properties格式,使用PropertyPlaceholderConfigurer来从单独文件中定义bean外部化属性值。

考虑以下基于 XML 的配置元数据片段,其中定义了带有占位符值:

image.png

该示例显示了从外部Properties文件配置的属性。在运行时,将PropertyPlaceholderConfigurer应用于替换数据源的某些属性的元数据。将要替换的值指定为${property-name}形式的占位符。

context名称空间,可以使用专用配置元素配置属性占位符。您可以在location属性中以逗号分隔列表的形式提供一个或多个位置,如以下示例所示:

image.png

image.png

因此,在运行时将${jdbc.username}字符串替换为值“ sa”,并且其他与属性文件中的键匹配的占位符值也是如此。

PropertyPlaceholderConfigurer不仅在您指定的Properties文件中查找属性。默认情况下,如果无法在指定的属性文件中找到属性,则还会检查 Java System属性。

可以通过使用以下三个受支持的整数值之一设置配置程序的systemPropertiesMode属性来自定义此行为:

image.png

image.png

示例:PropertyOverrideConfigurer:

类似于PropertyPlaceholderConfigurer,但是与后者不同,原始定义对于 Bean 属性可以具有默认值或完全没有值。如果覆盖的Properties文件没有某个 bean 属性的条目,则使用默认的上下文定义。

如果有多个PropertyOverrideConfigurer实例为同一个 bean 属性定义了不同的值,则由于覆盖机制,最后一个实例将获胜。

属性文件配置行采用以下格式:beanName.property=value;

       示例:

              image.png

       此示例文件可与包含定义为dataSource且具有driver和url属性的 Bean 的容器定义一起使用。

       也支持复合属性名。在以下示例中,将tom bean 的fred属性的bob属性的sammy属性设置为标量值123:

              image.png

context名称空间,可以使用专用配置元素配置属性覆盖,如以下示例所示:

image.png

1.8.3:使用FactoryBean自定义实例化逻辑:

您可以为本身就是工厂的对象实现org.springframework.beans.factory.FactoryBean接口。

FactoryBean接口是可插入 Spring IoC 容器的实例化逻辑点。如果您有复杂的初始化代码,而不是(可能)冗长的 XML,可以用 Java 更好地表达,则可以创建自己的FactoryBean,在该类中编写复杂的初始化,然后将自定义FactoryBean插入容器。

FactoryBean界面提供了三种方法:

       Object getObject():返回此工厂创建的对象的实例。实例可以共享,具体取决于该工厂是否返回单例或原型。

       boolean isSingleton():如果此FactoryBean返回单例,则返回true,否则返回false。

       Class getObjectType():返回由getObject()方法返回的对象类型或null (如果事先未知)。

当您需要向容器请求一个实际的FactoryBean实例本身而不是它生成的 bean 时,请在调用ApplicationContext的getBean()方法时在 bean 的id前面加上一个&符号(&)。