天天看點

Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用

Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用

上一篇博文已經介紹過怎麼去編譯​

​Spring Framework​

​​源碼了,其實很簡單,無非就是下載下傳依賴然後使用編譯器​

​build​

​項目。

  • ​​編譯 Spring Framework 5.2.17源碼 & 在源碼中使用 ApplicationContext 擷取定義的Bean​​

使用過​

​Spring​

​​系列架構進行開發的朋友應該都知道​

​Bean​

​​,它是​

​Spring IOC​

​​(控制反轉)或者說​

​DI​

​​(依賴注入)的基本機關,​

​Spring​

​​通過​

​BeanFactory​

​​來管理​

​Bean​

​​,使得我們不需要手動去執行個體化這些被依賴的​

​Bean​

​​,而是由​

​Spring​

​​的​

​BeanFactory​

​​去發現這些​

​Bean​

​​之間的依賴關系,以便确認目前需要的​

​Bean​

​的執行個體化先後順序;當然實作這些功能還是有點複雜的,從源碼中也可以看出,這裡隻是簡單的概述;看源碼不能急躁,一步一步去探索,最後發現沒有盡頭(ㄒoㄒ)。

比如​

​AbstractBeanFactory​

​​中的​

​doGetBean​

​​方法就有保證對目前​

​Bean​

​​所依賴的​

​Bean​

​進行初始化。

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);

        // 保證對目前bean所依賴的bean進行初始化。
        String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
          for (String dep : dependsOn) {
            if (isDependent(beanName, dep)) {
                // beanName和dep之間存在循環依賴關系
              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            registerDependentBean(dep, beanName);
            try {
              getBean(dep);
            }
            catch (NoSuchBeanDefinitionException ex) {
              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                  "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
            }
          }
        }      

上面隻是為了引出​

​Bean​

​​以及​

​BeanFactory​

​的一些概念,實際上要複雜的多,部落客也會在以後的部落格中進行詳細介紹。

很顯然​

​BeanFactory​

​​能夠感覺到​

​Bean​

​​的存在(​

​ApplicationContext​

​​(應用上下文)的實作類通過一些工具類來解析注解定義、類路徑資訊以及​

​XML​

​​配置檔案等​

​Bean​

​​定義源來感覺​

​Bean​

​​,如​

​AnnotationConfigApplicationContext​

​​中的​

​AnnotatedBeanDefinitionReader​

​​、​

​ClassPathBeanDefinitionScanner​

​​以及​

​XmlWebApplicationContext​

​​中的​

​XmlBeanDefinitionReader​

​​等),并且建立和管理這些​

​Bean​

​。

Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用

但​

​Bean​

​​怎麼感覺到​

​BeanFactory​

​​的存在呢?,我們定義​

​Bean​

​​,一般就直接加注解或者在​

​XML​

​​配置檔案中進行定義,但這些定義不會涉及到​

​BeanFactory​

​​的資訊,​

​BeanFactory​

​​就像是一個黑盒子;那現在就有一個問題了,當我們定義的​

​Bean​

​​需要知道​

​BeanFactory​

​​的一些資訊該怎麼辦呢?這就是​

​Aware​

​​接口及其實作類的工作了,而​

​aware​

​也有意識到的意思,也就是意識到​

​BeanFactory​

​中某些資訊的存在。

package org.springframework.beans.factory;

/**
 * A marker superinterface indicating that a bean is eligible to be notified by the
 * Spring container of a particular framework object through a callback-style method.
 * The actual method signature is determined by individual subinterfaces but should
 * typically consist of just one void-returning method that accepts a single argument.
 *
 * <p>Note that merely implementing {@link Aware} provides no default functionality.
 * Rather, processing must be done explicitly, for example in a
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * for an example of processing specific {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */
public interface Aware {}      

英文的大概意思:

  • 這是一個起标記作用的超接口,訓示​

    ​Bean​

    ​​可以通過回調形式的方法得到特定架構對象的Spring容器的通知。實際的方法由各個子接口決定(根據需要),但通常隻包含一個接受單個參數并且傳回​

    ​void​

    ​的方法。
  • 僅僅實作​

    ​Aware​

    ​​接口并不會提供預設功能。相反,處理必須顯式地完成,例如在​

    ​BeanPostProcessor​

    ​​接口中。參考​

    ​ApplicationContextAwareProcessor​

    ​​中處理特定​

    ​Aware​

    ​接口回調的例子。

先不深究​

​BeanPostProcessor​

​​的實作,隻需要知道在​

​Bean​

​​調用初始化方法的前後會調用​

​BeanPostProcessor​

​​中的方法,以便對​

​Bean​

​實作定制化。

​ApplicationContextAwareProcessor​

​​中的​

​postProcessBeforeInitialization​

​​方法就是在​

​Bean​

​​調用初始化方法之前會被調用,該方法又會調用​

​invokeAwareInterfaces​

​​方法,在該方法中就會調用​

​Aware​

​​接口實作類中的接受單個參數并且傳回​

​void​

​的方法。

class ApplicationContextAwareProcessor implements BeanPostProcessor {

  private final ConfigurableApplicationContext applicationContext;

  private final StringValueResolver embeddedValueResolver;


  /**
   * Create a new ApplicationContextAwareProcessor for the given context.
   */
  public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
    this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
  }


  @Override
  @Nullable
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
      return bean;
    }

    AccessControlContext acc = null;

    if (System.getSecurityManager() != null) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }

    if (acc != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
        invokeAwareInterfaces(bean);
        return null;
      }, acc);
    }
    else {
      invokeAwareInterfaces(bean);
    }

    return bean;
  }

  private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware) {
      ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
    }
    if (bean instanceof EmbeddedValueResolverAware) {
      ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
    }
    if (bean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
    }
    if (bean instanceof ApplicationEventPublisherAware) {
      ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
    }
    if (bean instanceof MessageSourceAware) {
      ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
    }
    if (bean instanceof ApplicationContextAware) {
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
    }
  }
}      

​EnvironmentAware​

​​、​

​EmbeddedValueResolverAware​

​​、​

​ResourceLoaderAware​

​​、​

​ApplicationEventPublisherAware​

​​、​

​MessageSourceAware​

​​以及​

​ApplicationContextAware​

​​都是​

​Aware​

​接口的子接口。

public interface ApplicationContextAware extends Aware {
  void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}      

是以,在​

​Bean​

​​調用初始化方法的前後,會有一些方法去調用​

​Aware​

​​接口實作類中的方法,進而實作通過回調形式的方法得到特定架構對象的​

​Spring​

​​容器的通知,這樣​

​Bean​

​​就可以擷取到​

​BeanFactory​

​的一些資訊了。

當然,還有一些​

​Aware​

​​接口的子接口,比如​

​BeanNameAware​

​​、​

​BeanClassLoaderAware​

​​、​

​BeanFactoryAware​

​​、​

​ServletContextAware​

​​以及​

​ServletConfigAware​

​​等,而這些子接口的回調是在其他類中實作的,​

​AbstractAutowireCapableBeanFactory​

​​抽象類和​

​ServletContextAwareProcessor​

​​類中。其實目前介紹過的​

​Aware​

​​子接口,在​

​Bean​

​​的整個生命周期中有所展現,以便讓​

​Bean​

​​感覺​

​BeanFactory​

​的各種資訊,實作特定的功能。

​AbstractAutowireCapableBeanFactory​

​​抽象類(繼承了​

​AbstractBeanFactory​

​抽象類):

private void invokeAwareMethods(String beanName, 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);
      }
    }
  }      

​ServletContextAwareProcessor​

​​類(實作了​

​BeanPostProcessor​

​接口):

@Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (getServletContext() != null && bean instanceof ServletContextAware) {
      ((ServletContextAware) bean).setServletContext(getServletContext());
    }
    if (getServletConfig() != null && bean instanceof ServletConfigAware) {
      ((ServletConfigAware) bean).setServletConfig(getServletConfig());
    }
    return bean;
  }      

到這裡大家應該知道​

​Aware​

​​接口及其實作類的作用了吧,其中的方法會在建立​

​Bean​

​​的過程中被回調,以便設定一些​

​BeanFactory​

​中的資訊。

在​

​Spring Framework​

​​ 源碼中建立一個子​

​Module​

​,在上一篇部落格中已經介紹過了,這裡就不贅述了。

Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用

​IMessageService​

​接口:

package com.kaven.service;

import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContextAware;

public interface IMessageService extends ApplicationContextAware, BeanFactoryAware {
  String getMessage();
}      

實作類​

​MessageServiceImpl​

​:

package com.kaven.service.impl;

import com.kaven.service.IMessageService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Service("message")
public class MessageServiceImpl implements IMessageService {
  @Override
  public String getMessage() {
    return "Hello Kaven";
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println("----------------MessageServiceImpl----------------------");
    System.out.println("setApplicationContext");
    System.out.println(applicationContext.getBeanDefinitionCount());
    System.out.println(applicationContext);
    System.out.println("----------------MessageServiceImpl----------------------");
  }

  @Override
  public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    System.out.println("----------------MessageServiceImpl----------------------");
    System.out.println("setBeanFactory");
    System.out.println(beanFactory);
    System.out.println("----------------MessageServiceImpl----------------------");
  }
}      

啟動類​

​Application​

​:

package com.kaven;

import com.kaven.service.IMessageService;
import com.kaven.service.impl.MessageServiceImpl;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;

import java.util.Arrays;

@ComponentScan({"com.kaven"})
public class Application implements BeanNameAware, EnvironmentAware {
  public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
    IMessageService service = (MessageServiceImpl) context.getBean("message");
    System.out.println(service.getMessage());
    System.out.println(context.getBeanDefinitionCount());
    Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
    ((Application)context.getBean("application")).print("Hello Kaven");
  }

  public void print(String str){
    System.out.println(str);
  }

  @Override
  public void setBeanName(String name) {
    System.out.println("---------Application----------");
    System.out.println(name);
    System.out.println("---------Application----------");
  }

  @Override
  public void setEnvironment(Environment environment) {
    System.out.println("---------Application----------");
    System.out.println(environment);
    System.out.println("---------Application----------");
  }
}      

輸出結果:

Spring Framework 源碼閱讀(一):Aware接口及其實作類的作用

顯然是可以的。