Spring - InstantiationAwareBeanPostProcessor 扩展接口

简介: InstantiationAwareBeanPostProcessor 扩展接口

@[toc]

在这里插入图片描述


Pre

Spring Boot - 扩展接口一览

在这里插入图片描述


org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

在这里插入图片描述

注意下: Initialization 表示 初始化 (意思是对象已经生成) 。 Instantiation 表示 实例化 (意思是对象还未生成) 。

接口继承了BeanPostProcess接口 , 从方法上我们也可以看出 InstantiationAwareBeanPostProcessor 做了一些扩展 。

BeanPostProcess接口只在bean的初始化阶段进行扩展(注入spring上下文前后),而InstantiationAwareBeanPostProcessor接口在此基础上增加了3个方法,使得扩展接口可以在实例化阶段和属性注入阶段

该类主要的扩展点有以下5个方法,主要在bean生命周期的两大阶段:实例化阶段 和初始化阶段

(1)实例化: 实例化的过程是一个创建Bean的过程,即调用Bean构造函数,单例的Bean入单例池中
(2)初始化: 初始化的过程是一个赋值的过程,即调用Bean的setter方法,设置Bean属性

InstantiationAwareBeanPostProcessor作用于过程(1)实例化前后; BeanPostProcessor用于过程(2)初始化前后


按调用顺序,我们来看一下

  • postProcessBeforeInstantiation:实例化bean之前,相当于new这个bean之前
  • postProcessAfterInstantiation:实例化bean之后,相当于new这个bean之后
  • postProcessPropertyValues: bean已经实例化完成,在属性注入时阶段触发, @Autowired,@Resource等注解原理基于此方法实现
  • postProcessBeforeInitialization:初始化bean之前,相当于把bean注入spring上下文之前
  • postProcessAfterInitialization:初始化bean之后,相当于把bean注入spring上下文之后

InstantiationAwareBeanPostProcessor 注册过程源码分析

我们还是从

org.springframework.context.support.AbstractApplicationContext#refresh

开始看 ,主要是下面两个方法

.......
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

.......

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

看下调用栈

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        org.springframework.beans.factory.support.AbstractBeanFactory#getBean
          org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean    
              org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean

createBean跟进去

@Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
    // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
    //省略....
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    return beanInstance;

    }

通过上面的代码,我们可以看到在执行doCreateBean之前有resolveBeforelnstantiation方法; 看注释

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
  • resolveBeforelnstantiation判断执行InstantiationAwareBeanPostProcessor.postProcessBeforelInstantiationg接口方法实现;
  • doCreateBean创建bean方法;

postProcessBeforeInstantiation的执行时机源码解析

org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
    BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        org.springframework.beans.factory.support.AbstractBeanFactory#getBean
          org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean    
              org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
                    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation

重点看 resolveBeforeInstantiation

    /**
     * Apply before-instantiation post-processors, resolving whether there is a
     * before-instantiation shortcut for the specified bean.
     * @param beanName the name of the bean
     * @param mbd the bean definition for the bean
     * @return the shortcut-determined bean instance, or {@code null} if none
     */
    @Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
        Object bean = null;
        //如果beforeInstantiationResolved还没有设置或者是false(说明还没有需要在实例化前执行的操作)
        if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
            // Make sure bean class is actually resolved at this point.
            // 判断是否有注册过InstantiationAwareBeanPostProcessor类型的bean
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                Class<?> targetType = determineTargetType(beanName, mbd);
                if (targetType != null) {
                    //执行
                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
            }
            mbd.beforeInstantiationResolved = (bean != null);
        }
        return bean;
    }

继续 applyBeanPostProcessorsBeforeInstantiation

    /**
     * Apply InstantiationAwareBeanPostProcessors to the specified bean definition
     * (by class and name), invoking their {@code postProcessBeforeInstantiation} methods.
     * <p>Any returned object will be used as the bean instead of actually instantiating
     * the target bean. A {@code null} return value from the post-processor will
     * result in the target bean being instantiated.
     * @param beanClass the class of the bean to be instantiated
     * @param beanName the name of the bean
     * @return the bean object to use instead of a default instance of the target bean, or {@code null}
     * @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
     */
    @Nullable
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        // 循环处理
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
            //只要有一个result不为null;后面的所有 后置处理器的方法就不执行了,直接返回(所以执行顺序很重要)
            if (result != null) {
                return result;
            }
        }
        return null;
    }

当然了也有 postProcessAfterInitialization

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

使用场景 : 创建代理类

 package com.artisan.bootspringextend.testextends;

import com.artisan.bootspringextend.service.ArtisanServiceImpl;
import com.artisan.bootspringextend.service.ClassA;
import com.artisan.bootspringextend.service.ClassAInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.annotation.Configuration;

/**
 * @author 小工匠
 * @version 1.0
 * @description:
 * @date 2022/11/28 0:33
 * @mark: show me the code , change the world
 */

@Slf4j
@Configuration
public class ExtendInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    private static final String VALUE = "classA";
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        if (VALUE.equals(beanName)) {
            log.info("4  beanName {}-----> postProcessBeforeInitialization", beanName);

        }
        return bean;
    }


    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (VALUE.equals(beanName)) {
            log.info("5   beanName {}-----> postProcessAfterInitialization", beanName);

        }

        return bean;
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {


        if (beanClass == ClassA.class) {
            log.info("1  beanName {} -----> postProcessBeforeInstantiation", beanName);

            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(beanClass);
            enhancer.setCallback(new ClassAInterceptor());

            ClassA classA = (ClassA) enhancer.create();
            log.info("proxy created ---->{}", classA.toString());

            return classA;
        }

        return null;
    }


    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {

        if (VALUE.equals(beanName)) {
            log.info("2   beanName {}-----> postProcessAfterInstantiation", beanName);

        }

        return false;
    }


    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {

        if (VALUE.equals(beanName)) {
            log.info("3   beanName {} -----> postProcessProperties", beanName);

        }
        return pvs;
    }
}
    
    

在这里插入图片描述

我们可以看到 InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation 生成了代理类后,直接执行了 初始化后的动作 BeanPostProcessor#postProcessAfterInitialization

在这里插入图片描述

相关文章
|
30天前
|
存储 安全 Java
|
1月前
|
自然语言处理 JavaScript Java
Spring 实现 3 种异步流式接口,干掉接口超时烦恼
本文介绍了处理耗时接口的几种异步流式技术,包括 `ResponseBodyEmitter`、`SseEmitter` 和 `StreamingResponseBody`。这些工具可在执行耗时操作时不断向客户端响应处理结果,提升用户体验和系统性能。`ResponseBodyEmitter` 适用于动态生成内容场景,如文件上传进度;`SseEmitter` 用于实时消息推送,如状态更新;`StreamingResponseBody` 则适合大数据量传输,避免内存溢出。文中提供了具体示例和 GitHub 地址,帮助读者更好地理解和应用这些技术。
227 0
|
2月前
|
存储 数据采集 Java
Spring Boot 3 实现GZIP压缩优化:显著减少接口流量消耗!
在Web开发过程中,随着应用规模的扩大和用户量的增长,接口流量的消耗成为了一个不容忽视的问题。为了提升应用的性能和用户体验,减少带宽占用,数据压缩成为了一个重要的优化手段。在Spring Boot 3中,通过集成GZIP压缩技术,我们可以显著减少接口流量的消耗,从而优化应用的性能。本文将详细介绍如何在Spring Boot 3中实现GZIP压缩优化。
339 6
|
1月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
40 0
|
3月前
|
JSON 安全 Java
|
3月前
|
存储 SQL Java
|
3月前
|
JavaScript Java Spring
Spring Boot 接口返回文件流
Spring Boot 接口返回文件流
126 0
|
4月前
|
SQL Java 数据库
实时计算 Flink版产品使用问题之Spring Boot集成Flink可以通过什么方式实现通过接口启动和关闭Flink程序
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
监控 Java 应用服务中间件
Spring Boot应用的部署与扩展
Spring Boot应用的部署与扩展