您当前的位置:首页 > 电脑百科 > 程序开发 > 容器

Spring容器这些扩展点你都清楚了吗?

时间:2021-10-26 10:06:11  来源:  作者:Java网络研发架构师

环境:Spring5.3.10


通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。

使用BeanPostProcessor自定义bean

BeanPostProcessor接口定义回调方法,你可以实现这些方法来提供自己的(或覆盖容器的默认)实例化逻辑、依赖项解析逻辑等。如果希望在Spring容器完成bean的实例化、配置和初始化后实现一些自定义逻辑,可以编写一个或多个自定义BeanPostProcessor实现。

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

BeanPostProcessor实例对bean(或对象)实例进行操作。也就是说,SpringIoC容器实例化一个bean实例,然后BeanPostProcessor实例执行它们的工作。

BeanPostProcessor实例的作用域为每个容器。这仅在使用容器层次结构时才相关。如果在一个容器中定义BeanPostProcessor,它将只对该容器中的bean进行后期处理。换句话说,一个容器中定义的bean不会被另一个容器中定义的BeanPostProcessor后处理,即使两个容器都是同一层次结构的一部分。

要更改实际的bean定义(即定义bean的蓝图),您需要使用BeanFactoryPostProcessor,如使用BeanFactoryPostProcessor自定义配置元数据中所述。


org.springframework.beans.factory.config.BeanPostProcessor接口正好由两个回调方法组成。当此类类在容器中注册为后处理器时,对于容器创建的每个bean实例,后处理器在调用容器初始化方法(如InitializingBean.afterPropertiesSet()或任何声明的init方法)之前都会从容器中获取回调,在任何bean初始化回调之后。后处理器可以对bean实例执行任何操作,包括完全忽略回调。bean后处理器通常检查回调接口,或者用代理包装bean。一些SpringAOP基础设施类被实现为bean后处理器,以提供代理包装逻辑。

ApplicationContext自动检测在实现BeanPostProcessor接口的配置元数据中定义的任何bean。ApplicationContext将这些bean注册为后处理器,以便稍后在创建bean时调用它们。Bean后处理器可以像其他Bean一样部署在容器中。

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

以编程方式注册BeanPostProcessor实例

虽然推荐的BeanPostProcessor注册方法是通过ApplicationContext自动检测(如前所述),但你可以使用addBeanPostProcessor方法以编程方式针对可配置的BeanFactory注册它们。当您需要在注册之前评估条件逻辑,甚至在层次结构中跨上下文复制bean后处理器时,这非常有用。但是,请注意,以编程方式添加的BeanPostProcessor实例不遵循有序接口。在这里,登记的顺序决定了执行的顺序。还请注意,以编程方式注册的BeanPostProcessor实例总是在通过自动检测注册的实例之前进行处理,而不考虑任何显式顺序。

BeanPostProcessor实例和AOP自动代理

实现BeanPostProcessor接口的类是特殊的,容器会对它们进行不同的处理。作为ApplicationContext特殊启动阶段的一部分,所有直接引用的BeanPostProcessor实例和bean都在启动时实例化。接下来,以排序方式注册所有BeanPostProcessor实例,并将其应用于容器中的所有其他bean。因为AOP自动代理是作为BeanPostProcessor本身实现的,所以无论是BeanPostProcessor实例还是它们直接引用的Bean都不符合自动代理的条件,因此,它们没有编织方面。

对于任何这样的bean,您都应该看到一条信息性日志消息:bean someBean不符合由所有BeanPostProcessor接口处理的条件(例如:不符合自动代理的条件)。

如果您使用autowiring或@Resource(可能会返回到autowiring)将bean连接到BeanPostProcessor中,Spring在搜索类型匹配的依赖项候选项时可能会访问意外的bean,因此,使它们不符合自动代理或其他类型的bean后处理的条件。例如,如果你有一个用@Resource注释的依赖项,其中字段或setter名称不直接对应于bean的声明名称,并且没有使用name属性,那么Spring将访问其他bean以按类型匹配它们。

示例:

该示例显示了一个自定义BeanPostProcessor实现,该实现在容器创建每个bean时调用其toString()方法,并将结果字符串打印到系统控制台。

@Component
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {

  // 只需按原样返回实例化的bean
  public Object postProcessBeforeInitialization(Object bean, String beanName) {
    return bean; // 我们可能会在这里返回任何对象引用。。。
  }

  public Object postProcessAfterInitialization(Object bean, String beanName) {
    System.out.println("Bean '" + beanName + "' created : " + bean.toString());
    return bean;
  }
}

AutowiredAnnotationBeanPostProcessor

将回调接口或注释与自定义BeanPostProcessor实现结合使用是扩展Spring IOC容器的常用方法。Spring的
AutowiredAnnotationBeanPostProcessor就是一个例子 — BeanPostProcessor实现。

使用BeanFactoryPostProcessor自定义配置元数据

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

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

如果你想要更改实际的bean实例(即,从配置元数据创建的对象),那么您需要使用BeanPostProcessor(前面在使用BeanPostProcessor定制bean中描述)。虽然在技术上可以在BeanFactoryPostProcessor中使用bean实例(例如,通过使用BeanFactory.getBean()),但这样做会导致过早的bean实例化,违反标准容器生命周期。这可能会导致负面的副作用,例如绕过bean后处理。

此外,BeanFactoryPostProcessor实例的作用域为每个容器。这仅在使用容器层次结构时才相关。如果在一个容器中定义BeanFactoryPostProcessor,则它仅应用于该容器中的bean定义。一个容器中的Bean定义不会由另一个容器中的BeanFactoryPostProcessor实例进行后处理,即使两个容器都是同一层次结构的一部分。

bean工厂后处理器在ApplicationContext中声明时自动运行,以便对定义容器的配置元数据应用更改。Spring包括许多预定义的bean factory后处理器,如
PropertyOverrideConfiguler和PropertySourcePlaceHolderConfigurer。你还可以使用自定义BeanFactoryPostProcessor — 例如,注册自定义属性编辑器。

ApplicationContext自动检测部署到其中实现BeanFactoryPostProcessor接口的任何Bean。它在适当的时候将这些bean用作bean工厂的后处理器。你可以像部署任何其他bean一样部署这些后处理器bean。

属性占位符替换PropertySourcesPlaceholderConfigurer

通过使用标准JAVA属性格式,你可以使用
PropertySourcesPlaceholderConfigurer将bean定义中的属性值外部化到单独的文件中。这样做使部署应用程序的人员能够自定义特定于环境的属性,例如数据库URL和密码,而无需修改容器的主XML定义文件的复杂性或风险。

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
  <property name="locations" value="classpath:com/something/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>

运行时,
PropertySourcesPlaceholderConfigurer应用于替换数据源某些属性的元数据。要替换的值被指定为形式${property name}的占位符,它遵循Ant、log4j和JSP EL样式。

实际值来自标准Java属性格式的properties文件:

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

自定义BeanFactoryPostProcessor

public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    // 获取Person的BeanDefinition对象,修改属性name的值。
    BeanDefinition beanDefinition = beanFactory.getBeanDefinition("person") ;
    beanDefinition.getPropertyValues().addPropertyValue("name", "CNM") ;
    System.out.println("BeanFactoryPostProcessor") ;
  }

}

使用FactoryBean自定义实例化逻辑

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

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

FactoryBean<T> 接口提供三种方法:

  • T getObject(): 返回此工厂创建的对象的实例。实例可能是共享的,这取决于此工厂返回的是单例还是原型。
  • boolean isSingleton(): 如果此FactoryBean返回Singleton,则返回true,否则返回false。此方法的默认实现返回true。
  • Class<?> getObjectType(): 返回getObject()方法返回的对象类型,如果类型事先未知,则返回null。

FactoryBean概念和接口在Spring框架中的许多地方都有使用。超过50个FactoryBean接口的实现与Spring本身一起提供。

当你需要向容器请求一个实际的FactoryBean实例本身而不是它生成的bean时,在调用ApplicationContext的getBean()方法时,用符号(&)作为bean id的前缀。因此,对于id为myBean的给定FactoryBean,在容器上调用getBean("myBean")将返回FactoryBean的产品,而调用getBean("&myBean")将返回FactoryBean实例本身。

 

完毕!!!



Tags:Spring   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  Tags: Spring  点击:(20)  评论:(0)  加入收藏
今天来梳理下 Spring 的整体脉络啦,为后面的文章做个铺垫~后面几篇文章应该会讲讲这些内容啦 Spring AOP 插件 (了好久都忘了 ) 分享下 4ye 在项目中利用 AOP + MybatisPlus 对...【详细内容】
2021-12-07  Tags: Spring  点击:(14)  评论:(0)  加入收藏
&emsp;前面通过入门案例介绍,我们发现在SpringSecurity中如果我们没有使用自定义的登录界面,那么SpringSecurity会给我们提供一个系统登录界面。但真实项目中我们一般都会使用...【详细内容】
2021-12-06  Tags: Spring  点击:(18)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  Tags: Spring  点击:(25)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  Tags: Spring  点击:(55)  评论:(0)  加入收藏
1. 介绍1.1 介绍今天开始我们来学习Java操作MySQL数据库的技巧,Java操作MySQL是借助JdbcTemplate这个对象来实现的。JdbcTemplate是一个多数据库集中解决方案,而我们今天只讲...【详细内容】
2021-11-05  Tags: Spring  点击:(30)  评论:(0)  加入收藏
SpringBoot中的Controller注册本篇将会以Servlet为切入点,通过源码来看web容器中的Controller是如何注册到HandlerMapping中。请求来了之后,web容器是如何根据请求路径找到对...【详细内容】
2021-11-04  Tags: Spring  点击:(52)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Tags: Spring  点击:(33)  评论:(0)  加入收藏
环境:Springboot2.4.11环境配置接下来的演示都是基于如下接口进行。@RestController@RequestMapping("/exceptions")public class ExceptionsController { @GetMapping(...【详细内容】
2021-10-11  Tags: Spring  点击:(41)  评论:(0)  加入收藏
SpringBoot项目默认使用logback, 已经内置了 logback 的相关jar包,会从resource包下查找logback.xml, logback 文件格式范本 可直接复制使用,有控制台 info.log error.log三个...【详细内容】
2021-10-09  Tags: Spring  点击:(50)  评论:(0)  加入收藏
▌简易百科推荐
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  实战Java    Tags:Docker   点击:(10)  评论:(0)  加入收藏
在网页中渲染公式一直是泛学术工具绕不开的一个功能,最近更新产品功能,正巧遇到了这个需求,于是使用容器方式简单实现了一个相对靠谱的公式渲染服务。分享出来,希望能够帮到有类...【详细内容】
2021-12-01  编程菌zfn    Tags:Docker   点击:(10)  评论:(0)  加入收藏
1.1 docker命令直接部署1.1.1 拉取镜像docker pull wurstmeister/zookeeperdocker pull wurstmeister/kafka1.1.2 启动zookeeper容器docker run -d --name myzookeeper -p 2...【详细内容】
2021-11-15  无    Tags:docker   点击:(47)  评论:(0)  加入收藏
01 前言 顺着docker的发展,很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试,这篇文章主要讲述我们在docker中使用浏览器进行自动化测试如果可以...【详细内容】
2021-10-29  小码哥聊软件测试    Tags:Docker   点击:(42)  评论:(0)  加入收藏
因为你懂得的原因,下载docker镜像速度非常喜感,故收集几个国内常用的docker镜像。Docker中国区官方镜像地址:https://registry.docker-cn.com网易163的镜像http://hub-mirror.c...【详细内容】
2021-10-28  抓蛙程序猿    Tags:docker   点击:(48)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Java网络研发架构师    Tags:Spring   点击:(33)  评论:(0)  加入收藏
我们在很多场景下都需要做笔记,来对抗遗忘,一份好的笔记不仅能在需要的时候供我们查阅,也能帮助我们归纳整理知识提高做事效率。 目前市面上有很多云笔记软件,体验上各有不同,但...【详细内容】
2021-10-11  运维贼船    Tags:docker   点击:(61)  评论:(0)  加入收藏
1. Nacos官网Nacos Docker 快速开始2. Clone 项目git clone https://github.com/nacos-group/nacos-docker.git3. cd 到nacos-docker 路径下 直接启动即可cd nacos-dockerdo...【详细内容】
2021-09-16  程序狗爱化妆    Tags:Nacos   点击:(109)  评论:(0)  加入收藏
今天不做保姆级教程,分享奶爸常用、好用的Docker应用。有了这些Docker,Nas的可玩性会大幅提高,有时候奶爸也在想,刨去官方套件不考虑的话,Nas真的是差不多。如果小伙伴们有需要,后...【详细内容】
2021-09-03  晋升奶爸的垃圾佬    Tags:Docker   点击:(167)  评论:(0)  加入收藏
环境要求 ubuntu系统:20.04 docker版本:20.10.7 redis版本:6.0.6步骤由于我这里已经有相应的redis镜像,这里就不记录了,关于docker一些基础知识可以看我以前的笔记开启3台re...【详细内容】
2021-07-26  石老师小跟班    Tags:Redis主从复制   点击:(117)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条