前言

废话不多说,直接进入主题。

同学们有想过这么一种情况吗: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接口介绍的更多相关文章

  1. Spring之InstantiationAwareBeanPostProcessor接口介绍

      InstantiationAwareBeanPostProcessor接口是BeanPostProcessor的子接口,通过接口字面意思翻译该接口的作用是感知Bean实例话的处理器.实际上该接口的 ...

  2. Spring事务管理接口定义

    Spring事务管理接口介绍 Spring事务管理接口: PlatformTransactionManager: (平台)事务管理器 TransactionDefinition: 事务定义信息(事务隔 ...

  3. Spring8:一些常用的Spring Bean扩展接口

    前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...

  4. Spring中Ordered接口简介

    目录 前言 Ordered接口介绍 Ordered接口在Spring中的使用 总结 前言 Spring中提供了一个Ordered接口.Ordered接口,顾名思义,就是用来排序的. Spring是一个 ...

  5. Spring Resource框架体系介绍

    Resource介绍 在使用spring作为容器进行项目开发中会有很多的配置文件,这些配置文件都是通过Spring的Resource接口来实现加载,但是,Resource对于所有低级资源的访问都不够充 ...

  6. Spring家族主流成员介绍

    摘 要:Spring 就像一个大家族,有众多衍生产品例如 Boot,Security,JPA等等.但他们的基础都是Spring 的 IOC 和 AOP,IOC提供了依赖注入的容器,而AOP解决了面向切 ...

  7. spring boot 连接Mysql介绍

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  8. spring boot rest 接口集成 spring security(2) - JWT配置

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  9. spring boot rest 接口集成 spring security(1) - 最简配置

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

随机推荐

  1. bsearch的溢出问题

    在java中为了避免 low+high溢出,可以用无符号右移:正数高位补0,负数高位补1 int mid = (low + high) >>> 1; 如果是在c++中,那么需要先转换 ...

  2. 为 Virtual Box 中的 CentOS 6.6 配置本地DVD光盘做yum软件源

    因为virtual box 中的centos配置host-only共享win7上网,配置失败,所以只能使用Centos的 DVD 光盘来配置yum软件源.不然就没得完了. 1. 首先要在virtual ...

  3. linux配置文件的一些调优

    Linux中所有东西都是文件,一个socket就对应着一个文件描述符,因此系统配置的最大打开文件数以及单个进程能够打开的最大文件数就决定了socket的数目上限:但是linux是有文件句柄限制的,而且 ...

  4. linux下批量修改存有超大数据量IP文件中的IP内容以及去重排序

    作为一个linux的学徒,分享一下自己解决这个小问题的心得,在处理这个问题时使用了一个小技巧感觉很适用,个人发觉linux的终端真滴是非常强大,下面就详细地介绍这个问题以及解决办法吧 问题描述:由于要 ...

  5. 【原】基于 HAproxy 1.6.3 Keeplived 在 Centos 7 中实现mysql mariadb galera cluster 集群分发读写 —— 上篇

    前言 有一段时间没有写blogs,乘着周末开始整理下haproxy + keeplived 实现 mysql mariadb galera cluster 集群访问环境的搭建工作. 本文集中讲hapr ...

  6. CSS中vw和vh单位的使用

    vw——viewpoint width,视窗宽度,1vw等于视窗宽度的1%: vh——viewpoint height,视窗高度,1vh等于视窗高度的1%:例子:http://tutorialzine ...

  7. 第一篇 UEditor入门部署和体验

    UEditor 是由百度「FEX前端研发团队」开发的所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码. UEditor富文本编辑器,轻量, ...

  8. MAVEN整理(乘国庆还有时间,停下来整理一下)

    昨天写下了这篇博客(http://www.cnblogs.com/hzmark/p/131003Release.html),今天有时间,就这里一下第一篇内容. 换工作公司开发平台: WINDOWS+V ...

  9. android linker (1) —— __linker_init()

    ilocker:关注 Android 安全(新手) QQ: 2597294287 __linker_init() 在 begin.S 中被调用,并传入两个参数:sp(堆栈指针).#0. linker( ...

  10. CentOS 6.5安装MongoDB

    1.创建mongodb.repo文件在/etc/yum.repos.d/目录下创建文件mongodb.repo,它包含MongoDB仓库的配置信息,内容如下: [mongodb] name=Mongo ...