Spring的BeanPostProcesser接口介绍
前言
废话不多说,直接进入主题。
同学们有想过这么一种情况吗:Spring容器提供给我们的一些接口实现类并不能满足我们的要求,但是我们又不想重新写一个类,只想在原来类上修改一些属性?
举个例子,SpringMVC中通过<mvc:annotation-driven>标签自动生成的RequestMappingHandlerAdapter有个HandlerMethodArgumentResolverComposite类型的argumentResolvers属性,这个属性内部有个HandlerMethodArgumentResolver集合属性,最终会使用这个集合处理Controller中参数的问题。这部分的知识请参考:详解SpringMVC中Controller的方法中参数的工作原理
我们通过源码来看下这个属性的初始化过程:

然后处理参数的时候会遍历HandlerMethodArgumentResolver集合属性,这样自定义的HandlerMethodArgumentResolver的优先级就落后了。
如果我们想让自定义的HandlerMethodArgumentResolver在优先级提高,怎么办呢? 可以使用BeanPostProcessor接口实现。
Spring官方文档对BeanPostProcessor接口的定义:Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies. 简单翻译下:一个工厂钩子,允许对工厂中的bean实例进行自定义修改,比如标记接口或使用代理类包装bean。
实例讲解
首先看下BeanPostProcessor接口的定义:
public interface BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
接口很简单,2个方法。 看名字也知道,初始化之前的操作和初始化之后的操作。
参数bean代表工厂中的实例;beanName代表这个实例的名字;返回值代表最终使用的beanName这个名字的实例,可以用个包装类,也可以用原先的那个bean。
这里的实例就是我们要修改RequestMappingHandlerAdapter中argumentResolvers属性里的HandlerMethodArgumentResolver集合顺序。
BeanPostProcessor的实现类代码:
@Component
public class HandlerAdapterPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//初始化之前不改变,原bean返回
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof RequestMappingHandlerAdapter && beanName.equals("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0")) {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodArgumentResolver> resolvers = adapter.getArgumentResolvers();
//这里的resolvers是一个UnmodifiableList,因此需要重新new一个其他类型的List
List<HandlerMethodArgumentResolver> newList = new ArrayList(resolvers);
newList.add(0, new FormObjArgumentResolver());
adapter.setArgumentResolvers(Collections.unmodifiableList(newList));
}
return bean;
}
}
这里我们判断RequestMappingHandlerAdapter的时候根据beanName为org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0的进行判断。
这里简单说明一下这个beanName的问题,为什么我们写成这样: 楼主的配置文件中定义了1个RequestMappingHandlerAdapter(没有写id属性),又写了<mvc:annotation-driven/>这句配置,且自定义的配置顺序在<mvc:annotation-driven/>之前。 这样就产生了2个RequestMappingHandlerAdapter,name分别为org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1。
当然可以给自定义的RequestMappingHandlerAdapter配置id属性,这样自定义的RequestMappingHandlerAdapter的beanName为配置的id属性,而<mvc:annotation-driven/>配置的RequestMappingHandlerAdapter的beanName为org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0。参考资料:Spring中Ordered接口简介
注意,我们加了@Component注解,在配置文件中需要配置component-scan扫描到这个类,Spring容器会自动查询实现了BeanPostProcessor接口的实现类并执行该接口定义的方法。
我们这里仅仅在第一个位置加入了FormObjArgumentResolver这个自定义的实现HandlerMethodArgumentResolver接口的类。
结果:

总结
在这里再次感叹Spring框架的强大,Spring预留给我们实现的接口太多了。 很多地方只需要实现某些接口,就会默认Spring的默认行为,而无需修改源码。 赞!
Spring的BeanPostProcesser接口介绍的更多相关文章
- Spring之InstantiationAwareBeanPostProcessor接口介绍
InstantiationAwareBeanPostProcessor接口是BeanPostProcessor的子接口,通过接口字面意思翻译该接口的作用是感知Bean实例话的处理器.实际上该接口的 ...
- Spring事务管理接口定义
Spring事务管理接口介绍 Spring事务管理接口: PlatformTransactionManager: (平台)事务管理器 TransactionDefinition: 事务定义信息(事务隔 ...
- Spring8:一些常用的Spring Bean扩展接口
前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...
- Spring中Ordered接口简介
目录 前言 Ordered接口介绍 Ordered接口在Spring中的使用 总结 前言 Spring中提供了一个Ordered接口.Ordered接口,顾名思义,就是用来排序的. Spring是一个 ...
- Spring Resource框架体系介绍
Resource介绍 在使用spring作为容器进行项目开发中会有很多的配置文件,这些配置文件都是通过Spring的Resource接口来实现加载,但是,Resource对于所有低级资源的访问都不够充 ...
- Spring家族主流成员介绍
摘 要:Spring 就像一个大家族,有众多衍生产品例如 Boot,Security,JPA等等.但他们的基础都是Spring 的 IOC 和 AOP,IOC提供了依赖注入的容器,而AOP解决了面向切 ...
- spring boot 连接Mysql介绍
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- spring boot rest 接口集成 spring security(2) - JWT配置
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
- spring boot rest 接口集成 spring security(1) - 最简配置
Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...
随机推荐
- Memcache限制端口和访问IP
Memcache安装十分简单,默认情况下是任何人都可以访问服务器上缓存的数据,所以如果不作处理的话 是很不安全的(乌云上已经提交有很多与此相关的问题) 1.首先要保证服务器上的防火墙都是开启的 2.设 ...
- PHP笔记(PHP高级篇)
高级篇中将涉及数据库的使用以及Cookie和Session会话,提高PHP的开发效率和运行效率 PHP程序员需要掌握的MySQL操作 为项目设计表 使用SQL语句 MySQL的目录结构 data目录中 ...
- 烂泥:U盘安装Centos6.5
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 使用U盘安装Centos6.5,需要以下几个步骤: 1. 制作U盘linux系统 2. 设置服务器BIOS 3. 安装Centos,注意引导分区的安装 ...
- ES5严格模式(Strict mode)
严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,第五版发布于2009年12月.旨在改善错误检查功能并且标识可能不会延续到未来JavaScript版本的脚本 ...
- 怎样用ZBrush雕刻人体造型
之前我们通过学习使用ZBrush®中的Curves和Insert笔刷快速创建模型的躯干.四肢以及手指.经过老师耐心的讲解我们也收获了很多,知道了创建模型的流程和雕刻技巧.今天的ZBrush教程我们将结 ...
- make命令--基础
一.Make的概念 Make这个词,英语的意思是"制作".Make命令直接用了这个意思,就是要做出某个文件.比如,要做出文件a.txt,就可以执行下面的命令. $ make a.t ...
- MySQL数据库学习笔记(五)----MySQL字符串函数、日期时间函数
一.常见字符串函数: 1.CHAR_LENGTH 获取长度(字符为单位) 2.FORMAT 格式化 3.INSERT 替换的方式插入 4.INSTR 获取位置 5.LEFT/RIGHT 取左 ...
- 第1章 UML基础:类的关系
1. 类的关系 1.1 继承和实现:继承表示有父子关系 1.2 依赖:(use–a),表示一个类要使用(use)另一个类. (1)类图 (2)三种依赖方式:函数参数或返回值.局部变量和静态成员变量或函 ...
- AC日记——潜伏者 洛谷 P1071 (模拟)
题目描述 R 国和 S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动.历尽艰险后,潜伏于 S 国的 R 国间谍小 C 终于摸清了 S 国军用密码的编码规则: 1. S 国军方内部欲发送的原 ...
- AC日记——神奇的幻方 洛谷 P2615(大模拟)
题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...