Spring 源碼-Spring Bean 的創建過程(12)

那隻斑馬還沒有睡 發佈 2022-05-16T17:58:35.226024+00:00

上一篇介紹了Spring在創建過程中doGetBean方法,在執行過程中會調用getSingleton方法並且設置一個lambda表達式,這個lambda表達式是ObjectFactory的實現,當調用這個接口的getObject方法時就會執行到createBean方法,在cre

上一篇介紹了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。

在Spring中Bean的創建分為實例化+初始化,當然還有屬性填充,這裡進行提前實例化其實就是給了一個擴展點,讓對象可以提前創建,而不用再繼續走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對象。


如果本文對你有幫助,別忘記給我個3連 ,點讚,轉發,評論,,咱們下期見。

收藏 等於白嫖,點讚才是真情。



原文 https://www.cnblogs.com/redwinter/p/16257638.html

關鍵字: