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执行流程图

image

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

结果:

image

BeanPostProcessor源码

注入BeanPostProcessor到BeanFactory

image

其中的逻辑就是使用getBean方法加载BeanPostProcessor类型的bean,然后添加到BeanFactory中的this.beanPostProcessors变量中。

执行BeanPostProcessor接口的方法

getBean方法 -> createBean方法 -> doCreateBean方法 -> initializeBean方法 -> BeanPostProcessor.postProcessBeforeInitialization方法 -> invokeInitMethods方法 -> BeanPostProcessor.postProcessAfterInitialization方法

image

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

image

posted @ 2023-06-05 23:19  sunpeiyu  阅读(82)  评论(0编辑  收藏  举报