Spring 的前置处理器介绍
SpringIOC容器它会以某种方式,加载配置文件中的 信息,将其解析为一个个的BeanDefinition.之后将BeanDefinition注册到容器之中。Spring IOC容器在实现的时候经过的过程可以使用如下图片表示:
分为两个主要部分:
其一 :容器启动阶段
其二:bean实例化阶段。
在容器的启动阶段主要做的是一些信息收集的过程(主要依赖于工具类BeanDefinitionReader),将收集的信息组成BeanDefinition.将BeanDefinition注册到相应的BeaneanRegistry.
Bean实例化的过程在请求方通过容器的getBean方法明确请求某个对象时候触发/隐式依赖关系调用时候也会触发该动作。此阶段做的操作主要是判断当前的请求对象是否已经被实例化过了。根据情况进行注入。当该对象实现某些回调接口。也会根据回调函数接口装配它
容器的前置处理 BeanFactoryPostProcess:
此后内容主要是对于容器实现第一阶段进行处理。Spring提供了容器扩展机制BeanFactoryPostProcess。这个机制允许我们在实例化相应对象之前对注册到容器中的BeanDefinition的存储信息进行修改。可以根据这个机制对Bean增加其它信息。修改Bean定义的某些属性值。
想自定义前置处理器需要实现BeanFactoryPostProcess
接口。当一个容器存在多种前置处理的时候,可以让前置处理器的实现类同时继承Ordered
接口。
Spring容器提供了数种现成的前置处理器,常见的如:
PropertyPlaceholderConfigurer
:允许在xml文件中使用占位符。将占位符代表的资源单独配置到简单的Properties文件中加载PropertyOverrideConfigurer
:不同于PropertyPlaceholderConfigurer的是,该类用于处理容器中的默认值覆为新值的场景CustomEditorConfigurer
:此前的两个前置处理器处理的均是BeanDefinition.通过把BeanDefinition的数据修改达到目的。CustomEditorConfigurer没有对BeanDefinition做任何变动。负责的是将后期会用到的信息注册到容器之中。例如将类型转换器注册到BeanDefinition中。供BeanDefinition将获取到的String类型参数转换为需要的类型。
装配前置处理器
装配前置处理器分为两种情况。一种是普通的BeanFactory.一种是ApplicationContext.对于ApplicationContext可以自动识别并装配前置处理器。
ApplicationContext的装配可以直接用xml文件实现:
配置文件:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>propertyHolder.properties</value></list></property></bean>
代码:
ApplicationContext factory=new ClassPathXmlApplicationContext("simple.xml");
启动的时候自动装载前置增强bean。无须额外操作。
BeanFactory装配方式:
ConfigurableListableBeanFactory factory=new XmlBeanFactory(new ClassPathResource("simple.xml"));PropertyPlaceholderConfigurer configurer=new PropertyPlaceholderConfigurer();configurer.setLocation(new ClassPathResource("propertyHolder.properties"));configurer.postProcessBeanFactory(factory);
三种前置处理器
1.PropertyPlaceholderConfigurer前置处理器
应用场景:
不想将系统管理相关的业务配置信息混杂到XML文件中的时候,可以将文件配置到properties.如此可以在当系统参数发生变幻时候,只需修改properties配置文件。强化可读性的同时,也降低了维护难度。
代码:
配置文件
<bean id="propertyHolder" class="com.example.demo.postprocess.MyPropertyHolderBean"><property name="username"><value>${java.version}</value></property><property name="password" value="${propertyHolder.password}"></property></bean>
bean包:
package com.example.demo.postprocess;public class MyPropertyHolderBean {private String username;private String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public void say() {System.out.println("username:"+username+";password:"+password);}
}
装配测试:
ConfigurableListableBeanFactory factory=new XmlBeanFactory(new ClassPathResource("simple.xml"));PropertyPlaceholderConfigurer configurer=new PropertyPlaceholderConfigurer();configurer.setLocation(new ClassPathResource("propertyHolder.properties"));configurer.postProcessBeanFactory(factory);MyPropertyHolderBean bean=(MyPropertyHolderBean) factory.getBean("propertyHolder");bean.say();
分析:
对于PropertyPlaceholderConfigurer前置处理器的处理分步:
- 创建xml文件装配需要使用前置增强装配的bean,使用占位符,占用value值
- 创建properties文件,键值与xml中占位符名称一致
- 通过beanFactory装载BeanDefinition
- 创建PropertyPlaceholderConfigurer对象并把beanFactory作为入参,为beanFactory增加前置增强操作,替换BeanDefinition中的展位符
PropertyPlaceholderConfigurer前置增强不止会扫描装载的properties文件还会扫描System类下的属性。
PropertyPlaceholderConfigurer提供了三种默认的装载规则:
SYSTEM_PROPERTIES_MODE_FALLBACK
:默认的装载规则。当properties中存在的时候使用properties中的值,不存在的时候则选择System中的值SYSTEM_PROPERTIES_MODE_NEVER
:从不扫描System中的值SYSTEM_PROPERTIES_MODE_OVERRIDE
:扫描系统值,当与properties中的值冲突时候,采用System中的值
当不设置的时候默认采用的是SYSTEM_PROPERTIES_MODE_FALLBACK。可以通过PropertyPlaceholderConfigurer对象的
setSystemPropertiesMode()
方法或者setSystemPropertiesModeName()
方法,修改其扫描注入的规则。
本例子采用的BeanFactory方式进行测试,Application容器方式的方式装配起来更为简单。对于装配模式的设定可以在其bean定义的XML文件中使用注入的方式处理。
举例如:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>propertyHolder.properties</value></list></property><property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK"></property></bean>
其余的操作同正常的使用Application一样。十分简便。
2.PropertyOverrideConfigurer前置处理器
应用场景:
可以通过PropertyOverrideConfigurer对容器中任何想处理的bean定义中的信息进行覆盖替换
。如此当容器创建bean的时候其bean的属性值就不同于xml文件的值了。
代码:
配置文件:
<bean id="overrideBean" class="com.example.demo.postprocess.MyPropertyOverrideBean"><property name="username"><value>工具人</value></property><property name="password"><value>简单的密码</value></property></bean>
properties文件内容
overrideBean.username=\u6700\u65B0\u7684\u5DE5\u5177\u4EBA
overrideBean.password=\u6700\u65B0\u7684\u5BC6\u7801
测试用小Demo:
ConfigurableListableBeanFactory factory=new XmlBeanFactory(new ClassPathResource("simple.xml"));PropertyOverrideConfigurer configurer=new PropertyOverrideConfigurer();configurer.setLocation(new ClassPathResource("propertyOverride.properties"));configurer.postProcessBeanFactory(factory);MyPropertyOverrideBean bean=(MyPropertyOverrideBean)factory.getBean("overrideBean");bean.say();
分析:
PropertyOverrideConfigurer的用法与PropertyPlaceholderConfigurer的使用方式类似。不同之处在于PropertyOverrideConfigurer的properties文件中的键值是bean名加其内部属性。而PropertyPlaceholderConfigurer的键值是其占位符的名。其次两者值注入的方式一种是替换占位符,一种是覆盖旧有的值。同时PropertyOverrideConfigurer不存在扫描System的情况。
Spring还可以支持对其加密的properties进行处理。PropertyOverrideConfigurer
与PropertyPlaceholderConfigurer
均继承了PropertyResourceConfigurer
,PropertyResourceConfigurer中提供了一个方法convertPropertyValue()
方法,可以通过覆盖该方法对相应的配置项内容进行转换。
例子:
<bean id="dealWithReplace" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer"><property name="locations"><list><value>propertyOverride.properties</value></list></property><replaced-method name="convertPropertyValue" replacer="replaceMethod"></replaced-method></bean>
这里使用了方法替换的方式实现处理,使用继承的方式也可以,自行创建一个后置处理类,继承系统的后置处理类,之后重写其convertPropertValue()
即可。在此不给具体代码了。
方法替换类:
public class MyReplacePostProcess implements MethodReplacer{@Overridepublic Object reimplement(Object obj, Method method, Object[] args) throws Throwable {// TODO Auto-generated method stubreturn "对不起,"+obj.getClass().getSimpleName()+"的"+method.getName()+"被替换掉了";}}
其余的操作与之前例子一致,获得的结果是进行转换处理后的值。对于其Application的操作与PropertyPlaceholderConfigurer的类似在此也不加解释了。
3.CustomEditorConfigurer前置处理器
场景:
CustomEditorConfigurer与其余的两个前置处理器有所不同,它负责辅助性将后期会用到的信息注入到容器之中,本身对于BeanDefinition没有做任何变更
。
在使用配置文件配置参数的过程中会出现一种情况。配置文件中记载的数据都是String类型的,但是程序中的对象的类型却是多种多样的。想要完成这种转化,需要转化规则相关信息。CustomEditorConfigurer前置处理器负责的就是处理传递类型转换信息消息
的一种前置处理器。
对于Spring内部使用PropertyEditor
帮助我们把String转化为其它类型。每个对象类型对应一个的PropertyEditor.在做类型转换的过程中,采用默认JavaBean框架的PropertyEditor搜寻逻辑,继承对原生类型及Color,Font等类型的转化。
Sping还提供了部分的PropertyEditor:
StringArrayPropertyEditor
. :此类型会将符合CSV格式的字符串转化为String[] 数组的形式,默认为以“,”分割的字符串。可以选择字符串的分割方式。ByteArrayPropertyEditor,CharArrayPropertyEditor均属于功能的PropertyEditorClassEditor
:.根据String类型的class名称,将其转换为对应的class对象,效果与Class.forName(String)
类似,入参可以是一个String[]数组,以数组形式传入的场合其作用与ClassArrayPropertyEditor一致FileEditor
:Spring提供的 对应 File文件类型的PropertyEditor。同属于对资源进行定位类型的还包括InputStreamEditor
,URLEditor
等LocaleEditor
:针对Locale
类型的PropertyEditorPatternEditor
:针对Pattern
的PropertyEditor
以上的这些PropertyEditor容器默认会加载使用,即使不告诉容器如何对这些类型进行转换,容器依旧可以正确的进行转换工作。当我们需要转换的类型在以上PropertyEditor之外的场合。需要我们给出针对这种情况的自定义PropertyEditor,并且通过CustomEditorConfigurer告知容器,以让其可以实现正确的转化。
例子:
下面给出一个针对日期转换的PropertyEditor例子。对于Spring而言提供了个简便的实现自定义PropertyEditor的方法,通过实现PropertyEditor
接口太复杂的情况下,可以通过继承PropertyEditorSupport
类重写setAsText(String)
来实现自定义。
PropertyEditor代码:
public class DatePropertyEditor extends PropertyEditorSupport {@Overridepublic void setAsText(String text) throws IllegalArgumentException {// TODO Auto-generated method stubSimpleDateFormat format=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");try {Date dateValue=format.parse(text);setValue(dateValue);} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
xml配置文件:
<bean id="dateEditor" class="com.example.demo.postprocess.DateEditorBean"><property name="date"><value>2019/1/1 11:11:11</value></property></bean>
测试用代码:
ConfigurableListableBeanFactory factory=new XmlBeanFactory(new ClassPathResource("simple.xml"));CustomEditorConfigurer configurer=new CustomEditorConfigurer();Map<Class<?>, Class<? extends PropertyEditor>> map=new HashMap();DatePropertyEditor editor= new DatePropertyEditor();map.put(java.util.Date.class,editor.getClass());configurer.setCustomEditors(map);configurer.postProcessBeanFactory(factory);DateEditorBean bean=(DateEditorBean)factory.getBean("dateEditor");System.out.println(bean.getDate());
分析:
本例子使用继承PropertyEditorSuppot
自定义创建了一个字符串日期转换器。供给bean装配注入的时候使用。
具体操作方式分如下:
- 继承PropertyEditorSupport,重写其
setAsText()
方法。将处理后的值通过setValue()
的方式注入 - 定义bean,同时使用setter注入方式注入值
- 创建容器+前置处理器
CustomEditorConfigurer
对象, - 创建Map对象,将需要处理的类型的class与PropertyEditor对象的class对应上
- 使用CustomEditorConfigurer对象的
setCustomEditors()
将PropertyEditor注册 - 调用CustomEditorConfigurer对象的
postProcessBeanFactory()
告知容器前置处理的变更情况
至此容器前置增强内容结束,附上git代码地址:
github下载地址
Spring 的前置处理器介绍相关推荐
- Jmeter的元件使用介绍:前置处理器详解
Jmeter的前置处理器可以用来在取样器执行前做一些数据准备操作,也需要注意使用的作用域问题.常用的前置处理器有:用户参数.BeanShell预处理器.JDBC预处理器. 一.用户参数 [用户参数]与 ...
- spring中的前置处理器和后置处理器区别
背景: SpringIOC容器它会以某种方式,加载配置文件中的 信息,将其解析为一个个的BeanDefinition.之后将BeanDefinition注册到容器之中.Spring IOC容器在实现的 ...
- Spring Boot Actuator 使用介绍
Spring Boot Actuator 使用介绍 初识 Actuator 原生端点 应用配置类 度量指标类 操作控制类 近期在看<Spring Cloud 微服务实战>,由于时间过去几年 ...
- Spring入门篇——第6章 Spring AOP的API介绍
第6章 Spring AOP的API介绍 主要介绍Spring AOP中常用的API. 6-1 Spring AOP API的Pointcut.advice概念及应用 映射方法是sa开头的所有方法 如 ...
- 21天Jmeter打卡Day18 前置处理器_熟悉常用组件
21天Jmeter打卡Day18 前置处理器_熟悉常用组件 https://www.jianshu.com/p/84866b2315f8 前置处理器使用场景 1.准备测试数据 2.数据加密–BeanS ...
- Jmeter前置处理器和后置处理器的使用
JSON Extractor 如下发送请求后,此请求返回了一个json对象 点击下拉框选择json path tester,响应数据被格式化 如果要拿对象中的token就可以在下方输入token,并点 ...
- Spring中的IOC介绍
Spring中的IOC介绍 IOC(控制反转) IOC介绍 IOC是什么 IOC能做什么 Spring容器管理对象 1.maven管理依赖 2.给定容器的配置文件 3.IOC容器管理对象 4.通过容器 ...
- 服务器sas卡的作用,英特尔IOP34x处理器介绍
英特尔IOP34x处理器介绍 早在06年秋季的IDF大会上,英特尔就展示了新一代的IOP34x家族,可想而知IOP 33x家族更加久远.这代存储处理器整合了先进的数据保护.基于硬件的RAID 5/6( ...
- 我的Java Web之路 - Spring(1)- 介绍
文章目录 介绍 建模 生产.装配/组装的思想 再谈容器 Spring工作模式 Spring的好处 总结 介绍 Spring在目前Java和Java Web开发里面简直就是神一样的存在,就是无处不在.这 ...
最新文章
- SAP MM ME21N 创建PO时报错 - Net price in CNY becomes too large – 之对策
- 使用CSS实现三栏自适应布局(两边宽度固定,中间自适应)
- Xcode Git 使用
- 基本的JVM内存分配过程案例
- Embeded linux之移植boa
- python填充_python 实现矩阵填充0的例子
- 自定义插入子串、删除子串、替换子串函数
- 把文档所有的字体都缩小一号_美观且专业的macOS字体管理工具
- Podfile 解析最佳实践
- 【梦幻西游】12门派版一键端
- axure rp8 添加动态面板_Axure原型教程:使用动态面板简单实现三级菜单
- 腾讯信鸽海量移动推送服务是如何构建的
- FMCW雷达测速和测距原理介绍
- 基于51单片机的俄罗斯方块游戏
- 扫雷php,扫雷php
- 互联网之于人类社会进化的意义
- 【解决办法】ES文件浏览器无法播放该链接
- 三菱 FX5U PLC结构化4轴伺服机器人程序
- 一刀工具箱 - 经纬度查询
- Sentinel限流