Spring扩展点之BeanPostProcessor

只需低头努力,剩下的交给时光,时间会公平地帮你处理一切

BeanPostProcessor是Bean的后置处理器,在spring容器启动的过程中,会调用BeanPostProcessor中的方法来进行Bean的处理。
BeanPostProcessor接口中有两个方法:

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;
	}

}

从两个方法名就可以看出来,postProcessBeforeInitialization是在初始化之前调用,postProcessAfterInitialization是在初始化之后调用

需要注意的是,这两个方法都有default实现,默认实现是直接返回Bean,不对Bean做任何处理

关于接口的default实现方法,可以参考我的另外一篇博文《Java接口原来还可以这么玩》

源码分析

关于BeanPostProcessor的处理是在AbstractAutowireCapableBeanFactory中的initializeBean方法中

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()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			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()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

在initializeBean方法中会在invokeInitMethods方法调用之前、之后分别调用applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization,这两个方法就是用来处理BeanPostProcessor的,下面具体看一下:

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

这两个方法的逻辑很简单,都是循环调用BeanPostProcessor的方法,只不过一个是调用postProcessBeforeInitialization方法,一个是调用postProcessAfterInitialization方法

也就是说在initializeBean方法中调用invokeInitMethods方法之前会调用postProcessBeforeInitialization,调用invokeInitMethods之后会调用postProcessAfterInitialization方法,那我们一起来看看invokeInitMethods方法是干啥的

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.isTraceEnabled()) {
				logger.trace("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) bean).afterPropertiesSet();
			}
		}

		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

invokeInitMethods方法的逻辑也很清晰,做了两件事

  • 判断是不是InitializingBean,是的话就调用afterPropertiesSet
  • 判断是否有自己定义的initMethod,有的话就调用对应的方法

这是主线逻辑,忽略了很多细节,在看源码的时候注意甄别

从这里我们可以得到一个调用顺序

  • BeanPostProcessor->postProcessBeforeInitialization
  • InitializingBean -> afterPropertiesSet
  • bean -> initMethod
  • BeanPostProcessor->postProcessAfterInitialization

下面我们通过一个例子来看一下是不是这样一个调用顺序

一个例子

public class User implements InitializingBean {

    public User(String name,int age){
        System.out.println("调用构造方法");
        this.name = name;
        this.age = age;
    }

    public void initMethod(){
        System.out.println("调用Bean -> initMethod");
        this.name = "initMethod";
        this.age = 3;
    }

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("调用InitializingBean -> afterPropertiesSet");
        this.name = "afterPropertiesSet";
        this.age = 4;
    }
}

定义了一个User类,实现了InitializingBean接口,覆盖了其afterPropertiesSet方法,User类中有一个带参的构造方法,一个初始化的方法initMethod

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof User){
            ((User) bean).setName("postProcessBeforeInitialization");
        }
        System.out.println("调用BeanPostProcessor -> postProcessBeforeInitialization");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof User){
            ((User) bean).setName("postProcessAfterInitialization");
        }
        System.out.println("调用BeanPostProcessor -> postProcessAfterInitialization");
        return bean;
    }
}

MyBeanPostProcessor实现BeanPostProcessor接口,并且覆盖了其postProcessBeforeInitialization和postProcessAfterInitialization

@Component
public class Configuration {

    @Bean(initMethod = "initMethod")
    public User getUser(){
        return new User("开心果",2);
    }

    @Bean
    public BeanPostProcessor getBeanPostProcessor(){
        return new MyBeanPostProcessor();
    }
}

我们将User对象和MyBeanPostProcessor对象注册到Spring容器中,这里注意一下User对象指定了initMethod,对应的就是Spring源码分析中的用户自定义initMethod

public class Main {
    public static void main(String[] args){
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("org.kxg.springDemo.beanPostProcessor");
        User user = annotationConfigApplicationContext.getBean(User.class);
        System.out.println(user.getName());
    }
}

运行结果如下:

调用构造方法
调用BeanPostProcessor -> postProcessBeforeInitialization
调用InitializingBean -> afterPropertiesSet
调用Bean -> initMethod
调用BeanPostProcessor -> postProcessAfterInitialization
postProcessAfterInitialization

从运行结果中可以看到,所有的方法都是在调用构造方法之后执行的,执行顺序跟我们上面源码中分析的是一致的

总结一下

  • BeanPostProcessor是Bean的后置处理器,在spring容器启动的过程中,会调用BeanPostProcessor中的方法来进行Bean的处理
  • 调用顺序:
    • BeanPostProcessor->postProcessBeforeInitialization
    • InitializingBean -> afterPropertiesSet
    • bean -> initMethod
    • BeanPostProcessor->postProcessAfterInitialization

如果感觉对你有些帮忙,请收藏好,你的关注和点赞是对我最大的鼓励!
如果想跟我一起学习,坚信技术改变世界,请关注【Java天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您

Spring扩展点之BeanPostProcessor

上一篇:Spring中Bean的生命周期


下一篇:spring -- BeanPOSTProcessor