SpringBoot扩展功能之BeanPostProcessor
BeanPostProcessor接口作用
BeanPostProcessor作为bean的后置处理器,主要用于扩展bean,在bean实例化(createBeanInstance方法)前,执行BeanPostProcessor.postProcessBeforeInitialization方法,在bean实例后,执行执行BeanPostProcessor.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;
}
}
SpringBoot执行流程图
BeanPostProcessor用法 - 修改bean的属性
// 定义的bean
@Data
@Component
public class FirstSunpyBean {
private String name = "马大帅";
private Integer age = 52;
}
// 定义bean的后置处理器BeanPostProcessor
@Component
public class FirstSunpyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FirstSunpyBean) {
FirstSunpyBean firstSunpyBean = (FirstSunpyBean) bean;
firstSunpyBean.setName("范德彪");
firstSunpyBean.setAge(18);
return firstSunpyBean;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
// service服务层
@Slf4j
@Service
public class MenuServiceImpl {
public Map<String, String> testMenu() {
Map<String, String> resultMap = new HashMap<>();
FirstSunpyBean firstSunpyBean = SpringUtils.getBean(FirstSunpyBean.class);
resultMap.put("name", firstSunpyBean.getName());
resultMap.put("age", firstSunpyBean.getAge().toString());
return resultMap;
}
}
结果:
BeanPostProcessor源码
注入BeanPostProcessor到BeanFactory
其中的逻辑就是使用getBean方法加载BeanPostProcessor类型的bean,然后添加到BeanFactory中的this.beanPostProcessors变量中。
执行BeanPostProcessor接口的方法
getBean方法 -> createBean方法 -> doCreateBean方法 -> initializeBean方法 -> BeanPostProcessor.postProcessBeforeInitialization方法 -> invokeInitMethods方法 -> BeanPostProcessor.postProcessAfterInitialization方法
BeanPostProcessor失效场景
我们知道BeanPostProcessor.postProcessBeforeInitialization方法的执行时机在InitializingBean.afterPropertiesSet方法和init-method方法之前,如果BeanPostProcessor.postProcessBeforeInitialization方法返回为null,那么后面的初始化操作都将失败。或者有些bean不在初始化阶段还未实例化,那么BeanPostProcessor这个bean后置处理器执行也会失效。
例1,BeanPostProcessor造成@PostConstruct失效
@PostConstruct注解是在invokeInitMethods方法中执行的,BeanPostProcessor.postProcessBeforeInitialization方法在其前面执行。如果BeanPostProcessor.postProcessBeforeInitialization方法返回bean为null,那么@PostConsturct注解标识的方法不会执行。
@Data
@Slf4j
@Component
public class FirstSunpyBean {
private String name = "马大帅";
private Integer age = 52;
@PostConstruct
public void initMenu() {
log.info("==================> initMenu方法");
}
}
@Component
public class FirstSunpyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof FirstSunpyBean) {
return null;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}