• Spring 源码(12)Spring Bean 的创建过程(3)


    继续上一篇Spring Bean的创建过程的解读,上一篇介绍了Spring在创建过程中doGetBean方法,在执行过程中会调用getSingleton方法并且设置一个lambda表达式,这个lambda表达式是ObjectFactory的实现,当调用这个接口的getObject方法时就会执行到createBean方法,在createBean方法中会进行bean类型的解析,并且会进行方法覆盖的设置,当我们配置了如:lookup-method或者replace-method方法的时候就会在创建Bean的过程中设置一个CGLIB的工厂类为Bean的对象,当调用的时候就会触发CGLIB的拦截器方法执行具体的Bean的获取,如果是单例对象引用了多例对象,那么就会每次创建一个新的对象给调用的方法执行。

    接下来继续解读Spring 创建Bean的过程。

    早期Bean的创建

    createBean方法中有一段代码:

    try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 解析提前实例化,使用InstantiationAwareBeanPostProcessor实现
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
        return bean;
      }
    }
    

    点进去:

    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
      Object bean = null;
      if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        // 判断是否有InstantiationAwareBeanPostProcessor在容器中
        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;
    }
    

    这里判断了容器中如果有实现InstantiationAwareBeanPostProcessor接口,那么就执行前置实例化,InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor,并且这个接口的方法跟BeanPostProcessor非常相似,InstantiationAwareBeanPostProcessor的接口一个是前置的实例化postProcessBeforeInstantiation,一个是后置的实例化postProcessAfterInstantiation,而BeanPostProcessor的接口一个是前置初始化postProcessBeforeInitialization,一个是后置初始化postProcessAfterInitialization

    SpringBean的创建分为实例化+初始化,当然还有属性填充,这里进行提前实例化其实就是给了一个扩展点,让对象可以提前创建,而不用再继续走doCreateBean方法里面的复杂逻辑,这样的话就提供给用户能够自己控制对象的创建过程以及执行增强等操作。

    那这个实例化增强类是何时放进Spring容器的呢?

    答案很简单,InstantiationAwareBeanPostProcessor是一个BeanPostProcessor,那么自然也就是在注册BeanPostProcessor时放进去的。

    看源码:

    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
      Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
      // Remove from old position, if any
      // 先删除掉旧的
      this.beanPostProcessors.remove(beanPostProcessor);
      // Track whether it is instantiation/destruction aware
      // 如果是InstantiationAwareBeanPostProcessor 设置属性
      if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
        this.hasInstantiationAwareBeanPostProcessors = true;
      }
      // 设置销毁的标识位
      if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
        this.hasDestructionAwareBeanPostProcessors = true;
      }
      // Add to end of list
      // 添加到链表尾
      this.beanPostProcessors.add(beanPostProcessor);
    }
    

    接下来试试提前实例化的案例:

    InstantiationAwareBeanPostProcessor 实验

    创建一个需要提前实例化的对象:

    /**
     * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
     * @since 1.0
     **/
    public class MyBeforeInstantiation {
    
    	public void beforeInvoke(){
    		System.out.println("提前实例化,开始执行业务....");
    	}
    }
    

    创建一个InstantiationAwareBeanPostProcessor的实现类:

    /**
     * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
     * @since 1.0
     **/
    public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    	@Override
    	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    		System.out.println("beanName: " + beanName + "执行了 postProcessBeforeInstantiation 方法");
    		// 提前进行实例化
    		if (beanClass == MyBeforeInstantiation.class) {
    			Enhancer enhancer = new Enhancer();
    			enhancer.setSuperclass(beanClass);
    			enhancer.setCallback(new MyMethodInterceptor());
    			Object obj = enhancer.create();
    			System.out.println("创建对象:" + obj);
    			return obj;
    		}
    		return null;
    	}
    
    	@Override
    	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
    		System.out.println("beanName: " + beanName + "执行了 postProcessAfterInstantiation 方法");
    		return false;
    	}
    
    	@Override
    	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    		System.out.println("beanName: " + beanName + "执行了 postProcessProperties 方法");
    		return pvs;
    	}
    
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("beanName: " + beanName + "执行了 postProcessBeforeInitialization 方法");
    		return bean;
    	}
    
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("beanName: " + beanName + "执行了 postProcessAfterInitialization 方法");
    		return bean;
    	}
    }
    

    这里使用了CGLIB 动态代理去增强创建代理对象,编写一个回调拦截器:

    /**
     * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
     * @since 1.0
     **/
    public class MyMethodInterceptor implements MethodInterceptor {
       @Override
       public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
          System.out.println("方法执行前:"+method);
          Object o1 = methodProxy.invokeSuper(o, objects);
          System.out.println("方法执行后:"+method);
          return o1;
       }
    }
    

    xml配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    	
    	<bean id="myBeforeInstantiation" class="com.redwinter.test.beforeInstantiation.MyBeforeInstantiation"/>
    	<bean id="myInstantiationAwareBeanPostProcessor" class="com.redwinter.test.beforeInstantiation.MyInstantiationAwareBeanPostProcessor"/>
    
    </beans>
    

    测试类:

    /**
     * @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
     * @since 1.0
     **/
    public class BeforeInstantiationTest {
    
      @Test
      public void test(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("before-instantiation.xml");
        MyBeforeInstantiation bean = ac.getBean(MyBeforeInstantiation.class);
        bean.beforeInvoke();
      }
    }
    

    输出:

    beanName: myBeforeInstantiation执行了 postProcessBeforeInstantiation 方法
    方法执行前:public java.lang.String java.lang.Object.toString()
    方法执行前:public native int java.lang.Object.hashCode()
    方法执行后:public native int java.lang.Object.hashCode()
    方法执行后:public java.lang.String java.lang.Object.toString()
    创建对象:com.redwinter.test.beforeInstantiation.MyBeforeInstantiation$$EnhancerByCGLIB$$f92db8b4@1fd3711
    beanName: myBeforeInstantiation执行了 postProcessAfterInitialization 方法
    方法执行前:public void com.redwinter.test.beforeInstantiation.MyBeforeInstantiation.beforeInvoke()
    提前实例化,开始执行业务....
    方法执行后:public void com.redwinter.test.beforeInstantiation.MyBeforeInstantiation.beforeInvoke()
    

    可以看到,这里只执行了两个方法,一个是postProcessBeforeInstantiation,是InstantiationAwareBeanPostProcessor的前置实例化接口,一个是postProcessAfterInitialization,是BeanPostProcessor的后置实例化接口。

    相当于说Bean对象提前被创建了,而没有执行下面的doCreateBean方法的逻辑。 Spring设计了很多的扩展点,帮助用户实现很多自定义的处理,Spring强大之处就在这里。

    这篇就介绍到这里,下一篇介绍Spring其他方式的进行提前创建Bean对象。

  • 相关阅读:
    微信小程序云开发-云函数发起https请求简易封装函数
    2022年金九银十Java面试手册宝典,横扫春招+校招+社招+秋招
    ​python联欢会评分 青少年编程电子学会python编程等级考试三级真题解析2020年9月
    Qt5下遍历QList的方法
    人工智能知识全面讲解:垃圾邮件克星——朴素贝叶斯算法
    Centos7上面安装uWSGI 部署项目测试
    word+excel+ppt 每日更新,雷打不动,faceface
    李沐大神动手学深度学习——学习笔记(连载)
    C++模板编程(9)---模板的多型(态)威力
    MacBook/MacOS如何更新到指定的版本
  • 原文地址:https://www.cnblogs.com/redwinter/p/16257638.html