Spring扩展接口-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;
    }
}

用途示例

Spring aop注入切面-BeanNameAutoProxyCreator

在目标bean初始化完成之后,包装之后返回一个代理对象,注入相关的切面逻辑。

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        //对原来的bean进行代理
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        //返回代理对象
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

监控 Bean 初始化耗时, 常用来排查Spring启动慢分析流程中,排查是否Bean初始化所致

@Service
@Slf4j
public class BeanInitMetrics implements BeanPostProcessor {

    private final Map<String, Long> stats = new HashMap<>();

    private final List<Metric> metrics = new ArrayList<>();

    @Data
    public static class Metric{

        public Metric() {
        }

        public Metric(String name, Integer value) {
            this.name = name;
            this.value = value;
            this.createDate = new Date();
        }

        private String name; //bean名称打印

        private Integer value; //bean耗时,单位为毫秒

        private Date createDate; //bean耗时的创建时间
    }

    //重写初始化接口
    @Override
    public Object postProcessBeforeInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException {
        stats.put(beanName, System.currentTimeMillis());
        return bean;
    }

    //后处理后初始化
    @Override
    public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException {
        Long start = stats.get(beanName);
        if (start != null) {
            metrics.add(new Metric(beanName, Math.toIntExact(System.currentTimeMillis() - start)));
        }
        return bean;
    }

    //通过后处理后初始化 - 初始化的时间算出bean耗时
    public List<Metric> getMetrics() {
        metrics.sort((o1, o2) -> {
            try {
                return o2.getValue() - o1.getValue();
            }catch (Exception e){
                return 0;
            }
        });
        log.info("metrics {}", JSON.toJSONString(metrics));
        return UnmodifiableList.unmodifiableList(metrics); //只读的集合
    }

}

更多信息请移步Spring专栏:www.yuque.com/mrhuang-ire…

参考: [1].zhuanlan.zhihu.com/p/617821971 [2].blog.csdn.net/weixin_4393…

posted @ 2023-10-12 10:07  扎Zn了老Fe  阅读(8)  评论(0编辑  收藏  举报  来源