Spring源码分析之BeanPostProcessor
文章目录1. BeanPostProcessor介绍1.1 postProcessBeforeInitialization方法和postProcessAfterInitialization方法调用时机2. 再看看BeanPostProcessor能做什么,有什么使用场景1. BeanPostProcessor介绍打开源码里面有两个方法,分别是postProcessBeforeInitializat
文章目录
1. BeanPostProcessor介绍
打开源码里面有两个方法,分别是postProcessBeforeInitialization和postProcessAfterInitialization。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
1.1 postProcessBeforeInitialization方法和postProcessAfterInitialization方法调用时机
通过方法名字看,它的执行时间是在对象初始化之前,这个初始化指的是bean对象的initMethod方法,也就是说postProcessBeforeInitialization只保证在自定义的initMethod之前执行。
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory的initializeBean方法
//注意此方法是在容器初始化后,实例化bean会自动调用,需要使用ApplicationContext容器才会自动初始化bean对象,BeanFacotry容器不会自动初始化对象,
//BeanFacotry只初始化容器,并且定义BeanDefinition,只有调用getBean才会触发对象初始化
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//调用了postProcessBeforeInitialization,读者朋友请自行打开applyBeanPostProcessorsBeforeInitialization跟踪源码,会发现里面调用了BeanPostProcessor的postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用出initMethod方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//调用postProcessAfterInitialization,和上面的调用了postProcessBeforeInitialization一个道理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
一开始我以为这个所谓的初始化之前和初始化之后值得是bean对象填充属性值的前后,比如下面初始化一个bean,填充对象name 和age,我一开始以为是先通过反射创建了一个空的(指的是name为null,age为0,并不是说对象是null)sonoBean对象,然后调用postProcessBeforeInitialization,这个理解是错误的,通过以上源码可以看出实际上是值得调用initMethod之前。
<bean id="sonoscape" class="com.chen.ioc.bean.SonoBean" scope="singleton" init-method="init">
<property name="age" value="3"></property>
<property name="name" value="tom"></property>
</bean>
2. 再看看BeanPostProcessor能做什么,有什么使用场景
一下自定义了一个BeanPostProcessor,我们使用postProcessBeforeInitialization来介绍一下使用场景,postProcessBeforeInitialization有两个参数,
-
bean:代表通过反射创建的对象,这个对象还未调用其initMethod方法
-
beanName:这个bean的名字
我们知道每个对象调用初始化方法之前都会调用BeanPostProcessor的postProcessBeforeInitialization方法,那么我们在postProcessBeforeInitialization方法既然能拿到bean对象,当然可以对它进行修改,比如,我想通过注解来给对对象属性设置默认值,可以看到在xml给bean设置了name和age,但是在postProcessBeforeInitialization中通过注解修改了name值,那么实际生效的name值实际上是注解上的那个。
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
log.warn("MyBeanPostProcessor init....");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
log.warn("[日志标志]: postProcessBeforeInitialization");
if (bean instanceof SonoBean) {
//获取注解
Custom custom = bean.getClass().getAnnotation(Custom.class);
SonoBean sonoBean = (SonoBean) bean;
//修改对象
sonoBean.setName(custom.name());
}
//返回修改后的对象
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
//Bean对象
@Custom(name = "zhangsan111", age = 22)
@Data
@Slf4j
public class SonoBean {
private String name;
private int age;
public SonoBean() {
log.warn("sono bean init..");
}
}
//自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Custom {
String value() default "";
int order() default 3;
String name() default "";
int age() default -1;
}
<bean id="sonoscape" class="com.chen.ioc.bean.SonoBean" scope="singleton" init-method="getAge">
<property name="age" value="3"></property>
<property name="name" value="tom"></property>
</bean>
postProcessAfterInitialization是在initMethod后执行,就不做过多分析了
3. bean的实例化过程
引用《spring内幕解密》中的图片,其实就是用图片的方式展示了第一步initializeBean方法中的过程
//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods
//InitializingBean的方法,是在invokeInitMethod方法中检查执行的,并且放在最前,所以它的afterPropertiesSet方法是在init-method之前
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//调用了InitializingBean的afterPropertiesSet
((InitializingBean的) bean).afterPropertiesSet();
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)