Spring之InstantiationAwareBeanPostProcessor接口介绍
InstantiationAwareBeanPostProcessor接口是BeanPostProcessor的子接口,通过接口字面意思翻译该接口的作用是感知Bean实例话的处理器。实际上该接口的作用也是确实如此。
Spring之BeanPostProcessor(后置处理器)介绍
InstantiationAwareBeanPostProcessor接口介绍
1.接口介绍
先来看下接口的源代码:
package org.springframework.beans.factory.config;
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
}
从源码中我们可以获知的信息是该接口除了具有父接口中的两个方法以外还自己额外定义了三个方法。所以该接口一共定义了5个方法,这5个方法的作用分别是
方法 | 描述 |
---|---|
postProcessBeforeInitialization | BeanPostProcessor接口中的方法, 在Bean的自定义初始化方法之前执行 |
postProcessAfterInitialization | BeanPostProcessor接口中的方法 在Bean的自定义初始化方法执行完成之后执行 |
postProcessBeforeInstantiation | 自身方法,是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走 |
postProcessAfterInstantiation | 在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true,postProcessPropertyValues就会被执行 |
postProcessPropertyValues | 对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改 |
注意两个单词
单词 | 含义 |
---|---|
Instantiation | 表示实例化,对象还未生成 |
Initialization | 表示初始化,对象已经生成 |
2.举例说明
1).创建接口实现类
/**
* 自定义处理器
* @author dengp
*
*/
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{
/**
* BeanPostProcessor接口中的方法
* 在Bean的自定义初始化方法之前执行
* Bean对象已经存在了
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println(">>postProcessBeforeInitialization");
return bean;
}
/**
* BeanPostProcessor接口中的方法
* 在Bean的自定义初始化方法执行完成之后执行
* Bean对象已经存在了
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("<<postProcessAfterInitialization");
return bean;
}
/**
* InstantiationAwareBeanPostProcessor中自定义的方法
* 在方法实例化之前执行 Bean对象还没有
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("--->postProcessBeforeInstantiation");
return null;
}
/**
* InstantiationAwareBeanPostProcessor中自定义的方法
* 在方法实例化之后执行 Bean对象已经创建出来了
*/
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("<---postProcessAfterInstantiation");
return true;
}
/**
* InstantiationAwareBeanPostProcessor中自定义的方法
* 可以用来修改Bean中属性的内容
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
String beanName) throws BeansException {
System.out.println("<---postProcessPropertyValues--->");
return pvs;
}
}
2).创建目标类
public class User {
private int id;
private String name;
private String beanName;
public User(){
System.out.println("User 被实例化");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("设置:"+name);
this.name = name;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void start(){
System.out.println("自定义初始化的方法....");
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", beanName=" + beanName + "]";
}
}
3).配置文件注册
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.dpb.pojo.User" id="user" init-method="start">
<property name="name" value="波波烤鸭"></property>
</bean>
<!-- 注册InstantiationAwareBeanPostProcessor对象 -->
<bean class="com.dpb.processor.MyInstantiationAwareBeanPostProcessor"></bean>
</beans>
4).测试
@Test
public void test1() {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = ac.getBean(User.class);
System.out.println(user);
// 关闭销毁
ac.registerShutdownHook();
}
输出结果
--->postProcessBeforeInstantiation
User 被实例化
<---postProcessAfterInstantiation
<---postProcessPropertyValues--->
设置:波波烤鸭
>>postProcessBeforeInitialization
自定义初始化的方法....
<<postProcessAfterInitialization
User [id=0, name=波波烤鸭, beanName=null]
通过输出结果,我们可以看到几个方法的执行顺序,而且五个方法都执行了,那么每个方法的返回结果对其他方法有什么影响没有呢,接下来分别看下这几个方法。
3.分析相关方法
1).postProcessBeforeInstantiation
该方法返回的结果如果为null,后面的方法都正常执行了,但是如果该方法返回了实例对象了呢?我们来看下
/**
* InstantiationAwareBeanPostProcessor中自定义的方法 在方法实例化之前执行 Bean对象还没有
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("--->postProcessBeforeInstantiation");
// 利用cglib动态代理生成对象返回
if (beanClass == User.class) {
Enhancer e = new Enhancer();
e.setSuperclass(beanClass);
e.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("目标方法执行前:" + method + "\n");
Object object = methodProxy.invokeSuper(obj, objects);
System.out.println("目标方法执行后:" + method + "\n");
return object;
}
});
User user = (User) e.create();
// 返回代理类
return user;
}
return null;
}
测试输出结果:
容器开始初始化....
--->postProcessBeforeInstantiation
User 被实例化
<<postProcessAfterInitialization
容器初始化结束....
通过数据结果我们发现,postProcessBeforeInstantiation方法返回实例对象后跳过了对象的初始化操作,直接执行了postProcessAfterInitialization(该方法在自定义初始化方法执行完成之后执行),跳过了postProcessAfterInstantiation,postProcessPropertyValues以及自定义的初始化方法(start方法),为什么会这样呢?我们要来查看下源代码。
在AbstractBeanFactory中的对InstantiationAwareBeanPostProcessor实现该接口的BeanPostProcessor 设置了标志
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
}
在AbstractAutowireCapableBeanFactory类中有个createBean方法,
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
// ... 省略
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
// ... 省略
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);这行代码之后之后根据bean判断如果不为空null就直接返回了,而不执行doCreateBean()方法了,而该方法是创建Bean对象的方法。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// //如果beforeInstantiationResolved还没有设置或者是false(说明还没有需要在实例化前执行的操作)
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// 判断是否有注册过InstantiationAwareBeanPostProcessor类型的bean
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
// 直接执行自定义初始化完成后的方法,跳过了其他几个方法
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
//只要有一个result不为null;后面的所有 后置处理器的方法就不执行了,直接返回(所以执行顺序很重要)
if (result != null) {
return result;
}
}
}
return null;
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
result = processor.postProcessAfterInitialization(result, beanName);
//如果返回null;后面的所有 后置处理器的方法就不执行,直接返回(所以执行顺序很重要)
if (result == null) {
return result;
}
}
return result;
}
代码说明:
- 如果postProcessBeforeInstantiation方法返回了Object是null;那么就直接返回,调用doCreateBean方法();
- 如果postProcessBeforeInstantiation返回不为null;说明修改了bean对象;然后这个时候就立马执行postProcessAfterInitialization方法(注意这个是初始化之后的方法,也就是通过这个方法实例化了之后,直接执行初始化之后的方法;中间的实例化之后 和 初始化之前都不执行);
- 在调用postProcessAfterInitialization方法时候如果返回null;那么就直接返回,调用doCreateBean方法();(初始化之后的方法返回了null,那就需要调用doCreateBean生成对象了)
- 在调用postProcessAfterInitialization时返回不为null;那这个bean就直接返回给ioc容器了初始化之后的操作是这里面最后一个方法了;
2).postProcessAfterInstantiation
同样在
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 省略 。。
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 此处执行 postProcessAfterInstantiation方法
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
// postProcessAfterInstantiation 返回true与false决定
// continueWithPropertyPopulation
continueWithPropertyPopulation = false;
break;
}
}
}
}
// postProcessAfterInstantiation false
// continueWithPropertyPopulation 就为false 然后该方法就结束了!!!
if (!continueWithPropertyPopulation) {
return;
}
// 省略 ...
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 调用 postProcessPropertyValues方法
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 真正设置属性的方法。
applyPropertyValues(beanName, mbd, bw, pvs);
}
这个postProcessAfterInstantiation返回值要注意,因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返true,postProcessPropertyValues就会被执行
3).postProcessPropertyValues
在populateBean方法中我们已经看到了postProcessPropertyValues执行的位置了。我们来看下postProcessPropertyValues的效果
/**
* InstantiationAwareBeanPostProcessor中自定义的方法 可以用来修改Bean中属性的内容
*/
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
String beanName) throws BeansException {
System.out.println("<---postProcessPropertyValues--->");
if(bean instanceof User){
PropertyValue value = pvs.getPropertyValue("name");
System.out.println("修改前name的值是:"+value.getValue());
value.setConvertedValue("bobo");
}
return pvs;
}
配置文件中设值注入name属性
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.dpb.pojo.User" id="user" init-method="start">
<property name="name" value="波波烤鸭"></property>
</bean>
<!-- 注册InstantiationAwareBeanPostProcessor对象 -->
<bean class="com.dpb.processor.MyInstantiationAwareBeanPostProcessor"></bean>
</beans>
测试看输出
--->postProcessBeforeInstantiation
User 被实例化
<---postProcessAfterInstantiation
<---postProcessPropertyValues--->
修改前name的值是:TypedStringValue: value [波波烤鸭], target type [null]
设置:bobo
>>postProcessBeforeInitialization
自定义初始化的方法....
<<postProcessAfterInitialization
User [id=0, name=bobo, beanName=null]
容器初始化结束....
name的属性值被修改了。该方法执行的条件要注意postProcessAfterInstantiation返回true且postProcessBeforeInstantiation返回null。
最后总结
- InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置
- postProcessBeforeInstantiation方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
- postProcessAfterInstantiation方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true, postProcessPropertyValues就会被执行
- postProcessPropertyValues方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改
- 父接口BeanPostProcessor的2个方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目标对象被实例化之后,并且属性也被设置之后调用的
Spring之InstantiationAwareBeanPostProcessor接口介绍的更多相关文章
- Spring的BeanPostProcesser接口介绍
前言 废话不多说,直接进入主题. 同学们有想过这么一种情况吗:Spring容器提供给我们的一些接口实现类并不能满足我们的要求,但是我们又不想重新写一个类,只想在原来类上修改一些属性? 举个例子,Spr ...
- 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 ...
随机推荐
- DataStructs.h
#ifndef _DATASTRUCS_H__ #define _DATASTRUCS_H__ #include <systemc.h> #include "GlobalPara ...
- Problem creating zip: Execution exce ption (and the archive is probably corrupt but I could not delete it): Java heap space -> [Help 1]
今天mvn编译的时候报错: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.5.5:s ...
- 更改MAC地址,突破公司绑定MAC地址的限制
步骤/方法 1 打开开始菜单,选择控制面板. 2 3 打开控制面板项,选择网络和共享中心. 4 5 选择更改适配器设置. 6 7 选择本地要修改MAC地址的网卡. 8 9 右键该网卡, ...
- UEditor可以如何直接复制word的图文内容到编辑器中?
下载并打开工程: 文档的上传 运行: 复制随便一篇文档,粘贴进去. 通过粘贴后,文档以及图片被粘贴进来了,看看html代码: 图片全部使用img标签统一.传输进度条的效果也不错. 文档图片被放置在 ...
- ASCII、Unicode、UTF-8以及Python3编码问题
编码问题,其实的确是个很烦人的问题,一开始觉得不需要看,到后来出现问题,真的是抓狂, 而像我们这些刚刚涉及到这些问题的小白来说,更是无从下手,所以查阅资料,总结理解下各个概念以及Python3的编码问 ...
- android 界面设计
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetric ...
- 推导正交投影(Orthographic Projection)
定义六个面 left right bottom top near far 然后三个轴分开考虑 x轴 视椎体的x范围在[l,r],我们要变换到[-1,1] 1 减去l变换到[0, r-l] 2 乘以 ...
- lua-01
ctrl + shift + L 多行编辑 ctrl + D 继续向下选中下一个相同的文本 Alt + F3 选中所有相同所选中德文本 =>Lua的快捷键 回调代码: function fact ...
- Chrome部分站点无法启用Flash问题
## 69.0之前 ## 1. 打开 chrome://settings/content/flash 2. 禁止网站运行Flash -> 改为“先询问(推荐)” 3. 允许->添加 4. ...
- 【渗透攻防WEB篇】SQL注入攻击初级
前言不管用什么语言编写的Web应用,它们都用一个共同点,具有交互性并且多数是数据库驱动.在网络中,数据库驱动的Web应用随处可见,由此而存在的SQL注入是影响企业运营且最具破坏性的漏洞之一,这里我想问 ...