<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          底層源碼分析 Spring 的核心功能和執(zhí)行流程(一)

          共 24982字,需瀏覽 50分鐘

           ·

          2021-07-20 12:56

          Spring Bean

          在 Spring 容器中管理一個(gè)或多個(gè) Bean,這些 Bean 的定義表示為 BeanDefinition 對(duì)象,這些對(duì)象包含以下重要信息:

          • Bean 的實(shí)際實(shí)現(xiàn)類(lèi)

          • Bean 的作用范圍

          • Bean 的引用或者依賴(lài)項(xiàng)

          Spring Bean 的作用域有哪些

          Bean 的作用域一共有 5 個(gè):

          1)singleton 作用域:表示在 Spring 容器中只有一個(gè) Bean 實(shí)例,以單例的形式存在,是默認(rèn)的 Bean 作用域。配置方式,缺省即可,XML 的配置方式如下:

          <bean class="..."></bean>

          2)prototype 作用域:原型作用域,每次調(diào)用 Bean 時(shí)都會(huì)創(chuàng)建一個(gè)新實(shí)例,也就是說(shuō)每次調(diào)用 getBean() 方法時(shí),相當(dāng)于執(zhí)行了 new Bean()。XML 的配置方式如下:

          <bean class="..." scope="prototype"></bean>

          3)request 作用域:每次 Http 請(qǐng)求時(shí)都會(huì)創(chuàng)建一個(gè)新的 Bean,該作用域僅適應(yīng)于 WebApplicationContext 環(huán)境。XML 的配置方式如下:

          <bean class="..." scope="request"></bean>

          Java 注解的配置方式如下:

          @Scope(WebApplicationContext.SCOPE_REQUEST)
          或者
          @RequestScope(WebApplicationContext.SCOPE_REQUEST)

          4)session 作用域:同一個(gè) Http Session 共享一個(gè) Bean 對(duì)象,不同的 Session 擁有不同的 Bean 對(duì)象,僅適用于 WebApplicationContext 環(huán)境。XML 的配置方式如下:

          <bean class="..." scope="session"></bean>

          Java 注解的配置方式如下:

          @Scope(WebApplicationContext.SCOPE_SESSION)
          或者
          @RequestScope(WebApplicationContext.SCOPE_SESSION)

          5)application 作用域:全局的 Web 作用域,類(lèi)似于 Servlet 中的 Application。XML 的配置方式如下:

          <bean class="..." scope="application"></bean>

          Java 注解的配置方式如下:

          @Scope(WebApplicationContext.SCOPE_APPLICATION)
          或者
          @RequestScope(WebApplicationContext.SCOPE_APPLICATION)

          它的注冊(cè)方式有幾種

          Bean 的注冊(cè)方式有三種:

          • XML 配置文件的注冊(cè)方式

          • Java 注解的注冊(cè)方式

          • Java API 的注冊(cè)方式

          具體實(shí)現(xiàn)方式如下:

          1. XML 配置文件注冊(cè)方式

          <bean id="person" class="org.springframework.beans.Person">

             <property name="id" value="1"/>

             <property name="name" value="Java"/>

          </bean>

          2. Java 注解注冊(cè)方式

          @Component

          public class Person {

             private Integer id;

             private String name

             // 忽略其他方法

          }

          @Configuration

          public class Person {

             @Bean

             public Person  person(){

                return new Person();

             }

             // 忽略其他方法

          }

          3. Java API 注冊(cè)方式

          使用
          BeanDefinitionRegistry.registerBeanDefinition() 方法的方式注冊(cè) Bean,代碼如下:

          public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {

          @Override

          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

          }

          @Override

          public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

          RootBeanDefinition personBean = new RootBeanDefinition(Person.class);

          // 新增 Bean

          registry.registerBeanDefinition("person", personBean);

          }

          }

          什么是同名 Bean?

          同名 Bean 指的是多個(gè) Bean 有相同的 name 或者 id。

          同名 Bean是如何產(chǎn)生的?

          同一個(gè) Spring 配置文件中 Bean 的 id 和 name 是不能夠重復(fù)的,否則 Spring 容器啟動(dòng)時(shí)會(huì)報(bào)錯(cuò)。但如果 Spring 加載了多個(gè)配置文件的話,可能會(huì)出現(xiàn)同名 Bean 的問(wèn)題。

          同名 Bean應(yīng)該如何避免?

          • Spring 對(duì)待同名 Bean 的處理規(guī)則是使用最后面的 Bean 覆蓋前面的 Bean,所以我們?cè)诙x Bean 時(shí),盡量使用長(zhǎng)命名非重復(fù)的方式來(lái)定義,避免產(chǎn)生同名 Bean 的問(wèn)題。

          • Bean 的 id 或 name 屬性并非必須指定,如果留空的話,容器會(huì)為 Bean 自動(dòng)生成一個(gè)唯一的名稱(chēng),這樣也不會(huì)出現(xiàn)同名 Bean 的問(wèn)題。

           Bean 的生命周期。

          生命周期如下圖:


          對(duì)于 Spring Bean 來(lái)說(shuō),并不是啟動(dòng)階段就會(huì)觸發(fā) Bean 的實(shí)例化,只有當(dāng)客戶(hù)端通過(guò)顯式或者隱式的方式調(diào)用 BeanFactory 的 getBean() 方法時(shí),它才會(huì)觸發(fā)該類(lèi)的實(shí)例化方法。當(dāng)然對(duì)于 BeanFactory 來(lái)說(shuō),也不是所有的 getBean() 方法都會(huì)實(shí)例化 Bean 對(duì)象,例如作用域?yàn)?singleton 時(shí),只會(huì)在第一次,實(shí)例化該 Bean 對(duì)象,之后會(huì)直接返回該對(duì)象。但如果使用的是 ApplicationContext 容器,則會(huì)在該容器啟動(dòng)的時(shí)候,立即調(diào)用注冊(cè)到該容器所有 Bean 的實(shí)例化方法。

          getBean() 既然是 Bean 對(duì)象的入口,我們就先從這個(gè)方法說(shuō)起,getBean() 方法是屬于 BeanFactory 接口的,它的真正實(shí)現(xiàn)是
          AbstractAutowireCapableBeanFactory 的 createBean() 方法,而 createBean() 是通過(guò) doCreateBean() 來(lái)實(shí)現(xiàn)的,具體源碼實(shí)現(xiàn)如下:

          @Override

          protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

                  throws BeanCreationException {

              if (logger.isTraceEnabled()) {

                  logger.trace("Creating instance of bean '" + beanName + "'");

              }

              RootBeanDefinition mbdToUse = mbd;

              // 確定并加載 Bean 的 class

              Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

              if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {

                  mbdToUse = new RootBeanDefinition(mbd);

                  mbdToUse.setBeanClass(resolvedClass);

              }

              // 驗(yàn)證以及準(zhǔn)備需要覆蓋的方法

              try {

                  mbdToUse.prepareMethodOverrides();

              }

              catch (BeanDefinitionValidationException ex) {

                  throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),

                          beanName, "Validation of method overrides failed", ex);

              }

              try {

                  // 給BeanPostProcessors 一個(gè)機(jī)會(huì)來(lái)返回代理對(duì)象來(lái)代替真正的 Bean 實(shí)例,在這里實(shí)現(xiàn)創(chuàng)建代理對(duì)象功能

                  Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

                  if (bean != null) {

                      return bean;

                  }

              }

              catch (Throwable ex) {

                  throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,

                          "BeanPostProcessor before instantiation of bean failed", ex);

              }

              try {

                  // 創(chuàng)建 Bean

                  Object beanInstance = doCreateBean(beanName, mbdToUse, args);

                  if (logger.isTraceEnabled()) {

                      logger.trace("Finished creating instance of bean '" + beanName + "'");

                  }

                  return beanInstance;

              }

              catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {

                  throw ex;

              }

              catch (Throwable ex) {

                  throw new BeanCreationException(

                          mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);

              }

          }

          doCreateBean 源碼如下:

          protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

                  throws BeanCreationException {

              // 實(shí)例化 bean,BeanWrapper 對(duì)象提供了設(shè)置和獲取屬性值的功能

              BeanWrapper instanceWrapper = null;

              // 如果 RootBeanDefinition 是單例,則移除未完成的 FactoryBean 實(shí)例的緩存

              if (mbd.isSingleton()) {

                  instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);

              }

              if (instanceWrapper == null) {

                  // 創(chuàng)建 bean 實(shí)例

                  instanceWrapper = createBeanInstance(beanName, mbd, args);

              }

              // 獲取 BeanWrapper 中封裝的 Object 對(duì)象,其實(shí)就是 bean 對(duì)象的實(shí)例

              final Object bean = instanceWrapper.getWrappedInstance();

              // 獲取 BeanWrapper 中封裝 bean 的 Class

              Class<?> beanType = instanceWrapper.getWrappedClass();

              if (beanType != NullBean.class) {

                  mbd.resolvedTargetType = beanType;

              }

              // 應(yīng)用 MergedBeanDefinitionPostProcessor 后處理器,合并 bean 的定義信息

              // Autowire 等注解信息就是在這一步完成預(yù)解析,并且將注解需要的信息放入緩存

              synchronized (mbd.postProcessingLock) {

                  if (!mbd.postProcessed) {

                      try {

                          applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

                      } catch (Throwable ex) {

                          throw new BeanCreationException(mbd.getResourceDescription(), beanName,

                                  "Post-processing of merged bean definition failed", ex);

                      }

                      mbd.postProcessed = true;

                  }

              }

              boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

                      isSingletonCurrentlyInCreation(beanName));

              if (earlySingletonExposure) {

                  if (logger.isTraceEnabled()) {

                      logger.trace("Eagerly caching bean '" + beanName +

                              "' to allow for resolving potential circular references");

                  }

                  // 為了避免循環(huán)依賴(lài),在 bean 初始化完成前,就將創(chuàng)建 bean 實(shí)例的 ObjectFactory 放入工廠緩存(singletonFactories)

                  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

              }

              // 對(duì) bean 屬性進(jìn)行填充

              Object exposedObject = bean;

              try {

                  populateBean(beanName, mbd, instanceWrapper);

                  // 調(diào)用初始化方法,如 init-method 注入 Aware 對(duì)象

                  exposedObject = initializeBean(beanName, exposedObject, mbd);

              } catch (Throwable ex) {

                  if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {

                      throw (BeanCreationException) ex;

                  } else {

                      throw new BeanCreationException(

                              mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);

                  }

              }

              if (earlySingletonExposure) {

                  // 如果存在循環(huán)依賴(lài),也就是說(shuō)該 bean 已經(jīng)被其他 bean 遞歸加載過(guò),放入了提早公布的 bean 緩存中

                  Object earlySingletonReference = getSingleton(beanName, false);

                  if (earlySingletonReference != null) {

                      // 如果 exposedObject 沒(méi)有在 initializeBean 初始化方法中被增強(qiáng)

                      if (exposedObject == bean) {

                          exposedObject = earlySingletonReference;

                      } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {

                          // 依賴(lài)檢測(cè)

                          String[] dependentBeans = getDependentBeans(beanName);

                          Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);

                          for (String dependentBean : dependentBeans) {

                              if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

                                  actualDependentBeans.add(dependentBean);

                              }

                          }

                          // 如果 actualDependentBeans 不為空,則表示依賴(lài)的 bean 并沒(méi)有被創(chuàng)建完,即存在循環(huán)依賴(lài)

                          if (!actualDependentBeans.isEmpty()) {

                              throw new BeanCurrentlyInCreationException(beanName,

                                      "Bean with name '" + beanName + "' has been injected into other beans [" +

                                              StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +

                                              "] in its raw version as part of a circular reference, but has eventually been " +

                                              "wrapped. This means that said other beans do not use the final version of the " +

                                              "bean. This is often the result of over-eager type matching - consider using " +

                                              "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");

                          }

                      }

                  }

              }

              try {

                  // 注冊(cè) DisposableBean 以便在銷(xiāo)毀時(shí)調(diào)用

                  registerDisposableBeanIfNecessary(beanName, bean, mbd);

              } catch (BeanDefinitionValidationException ex) {

                  throw new BeanCreationException(

                          mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);

              }

              return exposedObject;

          }

          從上述源碼中可以看出,在 doCreateBean() 方法中,首先對(duì) Bean 進(jìn)行了實(shí)例化工作,它是通過(guò)調(diào)用 createBeanInstance() 方法來(lái)實(shí)現(xiàn)的,該方法返回一個(gè) BeanWrapper 對(duì)象。BeanWrapper 對(duì)象是 Spring 中一個(gè)基礎(chǔ)的 Bean 結(jié)構(gòu)接口

          BeanWrapper 接口有一個(gè)默認(rèn)實(shí)現(xiàn)類(lèi) BeanWrapperImpl,其主要作用是對(duì) Bean 進(jìn)行填充,比如填充和注入 Bean 的屬性等。

          當(dāng) Spring 完成 Bean 對(duì)象實(shí)例化并且設(shè)置完相關(guān)屬性和依賴(lài)后,則會(huì)調(diào)用 Bean 的初始化方法 initializeBean(),初始化第一個(gè)階段是檢查當(dāng)前 Bean 對(duì)象是否實(shí)現(xiàn)了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 等接口,源碼如下:

          private void invokeAwareMethods(final String beanName, final Object bean) {

              if (bean instanceof Aware) {

                  if (bean instanceof BeanNameAware) {

                      ((BeanNameAware) bean).setBeanName(beanName);

                  }

                  if (bean instanceof BeanClassLoaderAware) {

                      ClassLoader bcl = getBeanClassLoader();

                      if (bcl != null) {

                          ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);

                      }

                  }

                  if (bean instanceof BeanFactoryAware) {

                      ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);

                  }

              }

          }

          其中,BeanNameAware 是把 Bean 對(duì)象定義的 beanName 設(shè)置到當(dāng)前對(duì)象實(shí)例中;BeanClassLoaderAware 是將當(dāng)前 Bean 對(duì)象相應(yīng)的 ClassLoader 注入到當(dāng)前對(duì)象實(shí)例中;BeanFactoryAware 是 BeanFactory 容器會(huì)將自身注入到當(dāng)前對(duì)象實(shí)例中,這樣當(dāng)前對(duì)象就會(huì)擁有一個(gè) BeanFactory 容器的引用。

          初始化第二個(gè)階段則是 BeanPostProcessor 增強(qiáng)處理,它主要是對(duì) Spring 容器提供的 Bean 實(shí)例對(duì)象進(jìn)行有效的擴(kuò)展,允許 Spring 在初始化 Bean 階段對(duì)其進(jìn)行定制化修改,比如處理標(biāo)記接口或者為其提供代理實(shí)現(xiàn)。

          在初始化的前置處理完成之后就會(huì)檢查和執(zhí)行 InitializingBean 和 init-method 方法。

          InitializingBean 是一個(gè)接口,它有一個(gè) afterPropertiesSet() 方法,在 Bean 初始化時(shí)會(huì)判斷當(dāng)前 Bean 是否實(shí)現(xiàn)了 InitializingBean,如果實(shí)現(xiàn)了則調(diào)用 afterPropertiesSet() 方法,進(jìn)行初始化工作;然后再檢查是否也指定了 init-method,如果指定了則通過(guò)反射機(jī)制調(diào)用指定的 init-method 方法,它的實(shí)現(xiàn)源碼如下:

          protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)

                  throws Throwable 
          {

              // 判斷當(dāng)前 Bean 是否實(shí)現(xiàn)了 InitializingBean,如果是的話需要調(diào)用 afterPropertiesSet()

              boolean isInitializingBean = (bean instanceof InitializingBean);

              if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {

                  if (logger.isTraceEnabled()) {

                      logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");

                  }

                  if (System.getSecurityManager() != null) { // 安全模式

                      try {

                          AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {

                              ((InitializingBean) bean).afterPropertiesSet(); // 屬性初始化

                              return null;

                          }, getAccessControlContext());

                      } catch (PrivilegedActionException pae) {

                          throw pae.getException();

                      }

                  } else {

                      ((InitializingBean) bean).afterPropertiesSet(); // 屬性初始化

                  }

              }

              // 判斷是否指定了 init-method()

              if (mbd != null && bean.getClass() != NullBean.class{

                  String initMethodName = mbd.getInitMethodName();

                  if (StringUtils.hasLength(initMethodName) &&

                          !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&

                          !mbd.isExternallyManagedInitMethod(initMethodName)) {

                      // 利用反射機(jī)制執(zhí)行指定方法

                      invokeCustomInitMethod(beanName, bean, mbd);

                  }

              }

          }

          初始化完成之后就可以正常的使用 Bean 對(duì)象了,在 Spring 容器關(guān)閉時(shí)會(huì)執(zhí)行銷(xiāo)毀方法,但是 Spring 容器不會(huì)自動(dòng)去調(diào)用銷(xiāo)毀方法,而是需要我們主動(dòng)的調(diào)用。

          如果是 BeanFactory 容器,那么我們需要主動(dòng)調(diào)用 destroySingletons() 方法,通知 BeanFactory 容器去執(zhí)行相應(yīng)的銷(xiāo)毀方法;如果是 ApplicationContext 容器,那么我們需要主動(dòng)調(diào)用 registerShutdownHook() 方法,告知 ApplicationContext 容器執(zhí)行相應(yīng)的銷(xiāo)毀方法。


          瀏覽 32
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本黄色视频免费网站 | 在线免费观看视频一区 | 日韩一极片 | 中文字幕无码在线 | A片在线免费 |