Spring源码分析之IOC的三种常见用法及源码实现(二)

  • 2019 年 10 月 20 日
  • 筆記

Spring源码分析之IOC的三种常见用法及源码实现(二)

回顾上文 我们研究的是

       AnnotationConfigApplicationContext annotationConfigApplication = new AnnotationConfigApplicationContext (MainConfig.class);           Person person2 = (Person)annotationConfigApplication.getBean("person2");

这两句话的实现,其中来到了主角儿AnnotationConfigApplicationContext的构造器实现:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {    this();    register(annotatedClasses);    refresh();  }

其中this()和register(annotatedClasses);看完了,我们这次来看看refresh();

一、跟进refresh()的代码

    public void refresh() throws BeansException, IllegalStateException {          synchronized (this.startupShutdownMonitor) {              // Prepare this context for refreshing.              prepareRefresh();                // Tell the subclass to refresh the internal bean factory.              ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();                // Prepare the bean factory for use in this context.              prepareBeanFactory(beanFactory);                try {                  // Allows post-processing of the bean factory in context subclasses.                  postProcessBeanFactory(beanFactory);                    // Invoke factory processors registered as beans in the context.                  invokeBeanFactoryPostProcessors(beanFactory);                    // Register bean processors that intercept bean creation.                  registerBeanPostProcessors(beanFactory);                    // Initialize message source for this context.                  initMessageSource();                    // Initialize event multicaster for this context.                  initApplicationEventMulticaster();                    // Initialize other special beans in specific context subclasses.                  onRefresh();                    // Check for listener beans and register them.                  registerListeners();                    // Instantiate all remaining (non-lazy-init) singletons.                  finishBeanFactoryInitialization(beanFactory);                    // Last step: publish corresponding event.                  finishRefresh();              }              catch (BeansException ex) {                  if (logger.isWarnEnabled()) {                      logger.warn("Exception encountered during context initialization - " +                              "cancelling refresh attempt: " + ex);                  }                  // Destroy already created singletons to avoid dangling resources.                  destroyBeans();                  // Reset 'active' flag.                  cancelRefresh(ex);                  // Propagate exception to caller.                  throw ex;              }              finally {                  // Reset common introspection caches in Spring's core, since we                  // might not ever need metadata for singleton beans anymore...                  resetCommonCaches();              }          }      }

讲这个之前铺垫一点前置基础知识

Spring中事件驱动开发

spring中是通过ApplicationListener及ApplicationEventMulticaster来进行事件驱动开发的,即实现观察者设计模式或发布-订阅模式。

ApplicationListener:监听容器中发布的事件,只要事件发生,就触发监听器的回调,来完成事件驱动开发。属于观察者设计模式中的Observer对象。

ApplicationEventMulticaster:用来通知所有的观察者对象,属于观察者设计模式中的Subject对象。

Spring后置处理器

BeanFactoryPostProcessor:继承这个的类它的实现方法可以在spring的bean定义好之后 而未实例化的时候做一些逻辑操作

BeanDefinitionRegistryPostProcessor:继承这个类它的实现方法可以在spring的bean未加载定义之前加些我们自己定义的bean定义

ok讲完了,回到代码。

我们铺垫了前置知识那么就对其中的

initApplicationEventMulticaster();

registerListeners();

进行讲解

二、refresh()中的initApplicationEventMulticaster

    protected void initApplicationEventMulticaster() {          ConfigurableListableBeanFactory beanFactory = getBeanFactory();          if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {              this.applicationEventMulticaster =                      beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);              if (logger.isDebugEnabled()) {                  logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");              }          }          else {              this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);              beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);              if (logger.isDebugEnabled()) {                  logger.debug("Unable to locate ApplicationEventMulticaster with name '" +                          APPLICATION_EVENT_MULTICASTER_BEAN_NAME +                          "': using default [" + this.applicationEventMulticaster + "]");              }          }      }

非常好懂,就一个if else,首先获取beanfactory,翻看源码知道这个beanfactory就是上篇文章讲的初始化父类时创建的DefaultListableBeanFactory,拿到这玩意。还是围绕这玩意的功能操作

接下来判断beanfactory里是不是有这个APPLICATION_EVENT_MULTICASTER_BEAN_NAME,翻看源码:

public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

是不是就是之前铺垫知识的listener?用来通知事件的。看看它在不在容器里面,不在的话走else创建一个,并且作为单例注册进去,在的话就从容器里面取出来赋值给当前this对象即我们的主角儿AnnotationConfigApplicationContext,而主角本身没定义这个是在主角父类AbstractApplicationContext里定义的,我们看看:

/** Helper class used in event publishing */  private ApplicationEventMulticaster applicationEventMulticaster;

看看,给了注释,辅助类 :用于事件派发的。

综上所述,这个initApplicationEventMulticaster()这行代码就是获取事件通知发布类的,没有的话就以单例创建一个放到容器并拿给主角儿,否则就直接拿到给主角儿。接下来看另一个registerListeners();

三、refresh()中的registerListeners();

源码如下:

    protected void registerListeners() {          // Register statically specified listeners first.          for (ApplicationListener<?> listener : getApplicationListeners()) {              getApplicationEventMulticaster().addApplicationListener(listener);          }            // Do not initialize FactoryBeans here: We need to leave all regular beans          // uninitialized to let post-processors apply to them!          String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);          for (String listenerBeanName : listenerBeanNames) {                 getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);          }            // Publish early application events now that we finally have a multicaster...          Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;          this.earlyApplicationEvents = null;          if (earlyEventsToProcess != null) {              for (ApplicationEvent earlyEvent : earlyEventsToProcess) {                  getApplicationEventMulticaster().multicastEvent(earlyEvent);              }          }      }  

第一个for循环是把所有listener都加到Multicaster里了(它用来通知相关事件)。其中

    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);      for (String listenerBeanName : listenerBeanNames) {             getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);      }

这个是从容器中拿ApplicationListener.class类型的,从名字也可以看出来getBeanForType,拿出来之后也放到Multicaster里(它用来通知相关事件),这也就是为什么我们可以自己实现ApplicationListener接口并且打上@Component注解之后能通知的原因了!它在这里加进去了。

最后一段是获取早期事件,获取了之后for循环进行触发事件。我们来看看它到底是个怎么触发的。

    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;      this.earlyApplicationEvents = null;      if (earlyEventsToProcess != null) {          for (ApplicationEvent earlyEvent : earlyEventsToProcess) {              getApplicationEventMulticaster().multicastEvent(earlyEvent);          }      }

打开里面的multicastEvent方法

    @Override      public void multicastEvent(ApplicationEvent event) {          multicastEvent(event, resolveDefaultEventType(event));      }  
    public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {          ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));          for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {              Executor executor = getTaskExecutor();              if (executor != null) {                  executor.execute(new Runnable() {                      @Override                      public void run() {                          invokeListener(listener, event);                      }                  });              }              else {                  invokeListener(listener, event);              }          }      }

一个解析类型、一个执行invokeListener,进去再看看这个咋invokeListener调用的

    protected void invokeListener(ApplicationListener listener, ApplicationEvent event) {          ErrorHandler errorHandler = getErrorHandler();          if (errorHandler != null) {              try {                  listener.onApplicationEvent(event);              }              catch (Throwable err) {                  errorHandler.handleError(err);              }          }          else {              try {                  listener.onApplicationEvent(event);              }              catch (ClassCastException ex) {                  String msg = ex.getMessage();                  if (msg == null || msg.startsWith(event.getClass().getName())) {                      // Possibly a lambda-defined listener which we could not resolve the generic event type for                      Log logger = LogFactory.getLog(getClass());                      if (logger.isDebugEnabled()) {                          logger.debug("Non-matching event type for listener: " + listener, ex);                      }                  }                  else {                      throw ex;                  }              }          }      }

仔细看下就发现重点了,其实最终就是调用listener.onApplicationEvent(event);,而这个onApplicationEvent就是ApplicationListener接口唯一的方法。换句话说,你只要实现这个接口类,并加入@Compent加入容器中,就会调用你实现类的onApplicationEvent里你自己的代码!

可能细心的同学会发现刚刚前面看到的registerListeners中最后一段里获取的是earlyApplicationEvents,这个early是什么意思?实际上是把Multicaster还没创建时就已经缓存的事件给获取播放,因为之前来了事件也不能丢掉啊。那么什么时候会有这个early事件呢?实际上是在refresh()代码里的registerListeners方法的前一句onRefresh方法中,这个方法默认是没有early事件的,会在springboot中使用.

至此registerListeners方法也讲完了。

接下来我们来讲讲refresh()中的invokeBeanFactoryPostProcessors(beanFactory);

四、refresh()中的invokeBeanFactoryPostProcessors(beanFactory);

    /**       * 按照明确的顺序实例化并调用所有在BeanFactoryPostProcessor注册的bean       * <p>Must be called before singleton instantiation.       */      protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {          PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());            // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime          // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)          if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {                beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));                beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));          }      }

很明显继续跟进这个invokeBeanFactoryPostProcessors同名方法:

    public static void invokeBeanFactoryPostProcessors(              ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {            // Invoke BeanDefinitionRegistryPostProcessors first, if any.          Set<String> processedBeans = new HashSet<String>();            if (beanFactory instanceof BeanDefinitionRegistry) {              BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;              List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();              List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =                      new LinkedList<BeanDefinitionRegistryPostProcessor>();                for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {                  if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {                      BeanDefinitionRegistryPostProcessor registryPostProcessor =                              (BeanDefinitionRegistryPostProcessor) postProcessor;                      registryPostProcessor.postProcessBeanDefinitionRegistry(registry);                      registryPostProcessors.add(registryPostProcessor);                  }                  else {                      regularPostProcessors.add(postProcessor);                  }              }                // Do not initialize FactoryBeans here: We need to leave all regular beans              // uninitialized to let the bean factory post-processors apply to them!              // Separate between BeanDefinitionRegistryPostProcessors that implement              // PriorityOrdered, Ordered, and the rest.              String[] postProcessorNames =                      beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);                // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.              List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();              for (String ppName : postProcessorNames) {                  if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {                      priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));                      processedBeans.add(ppName);                  }              }              sortPostProcessors(beanFactory, priorityOrderedPostProcessors);              registryPostProcessors.addAll(priorityOrderedPostProcessors);              invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);                // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.              postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);              List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();              for (String ppName : postProcessorNames) {                  if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {                      orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));                      processedBeans.add(ppName);                  }              }              sortPostProcessors(beanFactory, orderedPostProcessors);              registryPostProcessors.addAll(orderedPostProcessors);              invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);                // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.              boolean reiterate = true;              while (reiterate) {                  reiterate = false;                  postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);                  for (String ppName : postProcessorNames) {                      if (!processedBeans.contains(ppName)) {                          BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);                          registryPostProcessors.add(pp);                          processedBeans.add(ppName);                          pp.postProcessBeanDefinitionRegistry(registry);                          reiterate = true;                      }                  }              }                // Now, invoke the postProcessBeanFactory callback of all processors handled so far.              invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);              invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);          }            else {              // Invoke factory processors registered with the context instance.              invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);          }            // Do not initialize FactoryBeans here: We need to leave all regular beans          // uninitialized to let the bean factory post-processors apply to them!          String[] postProcessorNames =                  beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);            // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,          // Ordered, and the rest.          List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();          List<String> orderedPostProcessorNames = new ArrayList<String>();          List<String> nonOrderedPostProcessorNames = new ArrayList<String>();          for (String ppName : postProcessorNames) {              if (processedBeans.contains(ppName)) {                  // skip - already processed in first phase above              }              else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {                  priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));              }              else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {                  orderedPostProcessorNames.add(ppName);              }              else {                  nonOrderedPostProcessorNames.add(ppName);              }          }            // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.          sortPostProcessors(beanFactory, priorityOrderedPostProcessors);          invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);            // Next, invoke the BeanFactoryPostProcessors that implement Ordered.          List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();          for (String postProcessorName : orderedPostProcessorNames) {              orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));          }          sortPostProcessors(beanFactory, orderedPostProcessors);          invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);            // Finally, invoke all other BeanFactoryPostProcessors.          List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();          for (String postProcessorName : nonOrderedPostProcessorNames) {              nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));          }          invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);            // Clear cached merged bean definitions since the post-processors might have          // modified the original metadata, e.g. replacing placeholders in values...          beanFactory.clearMetadataCache();      }

仔细读里的逻辑会发现前半段是围绕:

            List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();              List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =                      new LinkedList<BeanDefinitionRegistryPostProcessor>();

这两个list进行不断筛选分类 然后进行invokeBeanDefinitionRegistryPostProcessors方法调用

而后半段是围绕:

        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();          List<String> orderedPostProcessorNames = new ArrayList<String>();          List<String> nonOrderedPostProcessorNames = new ArrayList<String>();

三个list进行分类添加进去,然后进行invokeBeanDefinitionRegistryPostProcessors方法调用

综上核心就是这个invokeBeanDefinitionRegistryPostProcessors的逻辑,我们来看看:

    private static void invokeBeanFactoryPostProcessors(              Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {            for (BeanFactoryPostProcessor postProcessor : postProcessors) {              postProcessor.postProcessBeanFactory(beanFactory);          }      }

遍历集合,并调用对应方法,继续查看源码:

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {          int factoryId = System.identityHashCode(beanFactory);          if (this.factoriesPostProcessed.contains(factoryId)) {              throw new IllegalStateException(                      "postProcessBeanFactory already called on this post-processor against " + beanFactory);          }          this.factoriesPostProcessed.add(factoryId);          if (!this.registriesPostProcessed.contains(factoryId)) {              // BeanDefinitionRegistryPostProcessor hook apparently not supported...              // Simply call processConfigurationClasses lazily at this point then.              processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);          }            enhanceConfigurationClasses(beanFactory);          beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));      }

设置注册id、然后这里显然主要逻辑在processConfigBeanDefinitions,继续查看:

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {          List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();          String[] candidateNames = registry.getBeanDefinitionNames();            for (String beanName : candidateNames) {              BeanDefinition beanDef = registry.getBeanDefinition(beanName);              if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||                      ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {                  if (logger.isDebugEnabled()) {                      logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);                  }              }              else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {                  configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));              }          }            // Return immediately if no @Configuration classes were found          if (configCandidates.isEmpty()) {              return;          }            // Sort by previously determined @Order value, if applicable          Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {              @Override              public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {                  int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());                  int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());                  return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;              }          });            // Detect any custom bean name generation strategy supplied through the enclosing application context          SingletonBeanRegistry sbr = null;          if (registry instanceof SingletonBeanRegistry) {              sbr = (SingletonBeanRegistry) registry;              if (!this.localBeanNameGeneratorSet && sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {                  BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);                  this.componentScanBeanNameGenerator = generator;                  this.importBeanNameGenerator = generator;              }          }            // Parse each @Configuration class          ConfigurationClassParser parser = new ConfigurationClassParser(                  this.metadataReaderFactory, this.problemReporter, this.environment,                  this.resourceLoader, this.componentScanBeanNameGenerator, registry);            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);          Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());          do {              parser.parse(candidates);              parser.validate();                Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());              configClasses.removeAll(alreadyParsed);                // Read the model and create bean definitions based on its content              if (this.reader == null) {                  this.reader = new ConfigurationClassBeanDefinitionReader(                          registry, this.sourceExtractor, this.resourceLoader, this.environment,                          this.importBeanNameGenerator, parser.getImportRegistry());              }              this.reader.loadBeanDefinitions(configClasses);              alreadyParsed.addAll(configClasses);                candidates.clear();              if (registry.getBeanDefinitionCount() > candidateNames.length) {                  String[] newCandidateNames = registry.getBeanDefinitionNames();                  Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));                  Set<String> alreadyParsedClasses = new HashSet<String>();                  for (ConfigurationClass configurationClass : alreadyParsed) {                      alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());                  }                  for (String candidateName : newCandidateNames) {                      if (!oldCandidateNames.contains(candidateName)) {                          BeanDefinition bd = registry.getBeanDefinition(candidateName);                          if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&                                  !alreadyParsedClasses.contains(bd.getBeanClassName())) {                              candidates.add(new BeanDefinitionHolder(bd, candidateName));                          }                      }                  }                  candidateNames = newCandidateNames;              }          }          while (!candidates.isEmpty());            // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes          if (sbr != null) {              if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {                  sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());              }          }            if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {              ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();          }      }

比较长,分几部分看,第一部分刚开始是创建一个ArrayList,类型是BeanDefinitionHolder,我们看看这个:

public class BeanDefinitionHolder implements BeanMetadataElement {      private final BeanDefinition beanDefinition;      private final String beanName;      private final String[] aliases;      .......  }

可以看出,这个BeanDefinitionHolder实际上就是个BeanDefinition的一个小包装。

继续看,后面的代码就是从registry容器中拿bean名字出来然后又根据名字把BeanDefinition拿出来,最后把名字和BeanDefinition本身一起装到list里面去了,再排个序。后面又创建了两bean名字生成器。

现在可以看到重点了,有一行注释:

        // Parse each @Configuration class          ConfigurationClassParser parser = new ConfigurationClassParser(                  this.metadataReaderFactory, this.problemReporter, this.environment,                  this.resourceLoader, this.componentScanBeanNameGenerator, registry);            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);          Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());          do {              parser.parse(candidates);              parser.validate();              ......          }while(....)              .....

这里来到了核心重点,要解析我们的配置类了!弄了个do while循环保证这些都list里的东西都解析完,我们来看看解析方法parser.parse(candidates);吧!它是怎么解析的:

    public void parse(Set<BeanDefinitionHolder> configCandidates) {          this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();            for (BeanDefinitionHolder holder : configCandidates) {              BeanDefinition bd = holder.getBeanDefinition();              try {                  if (bd instanceof AnnotatedBeanDefinition) {                      parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());                  }                  else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {                      parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());                  }                  else {                      parse(bd.getBeanClassName(), holder.getBeanName());                  }              }              catch (BeanDefinitionStoreException ex) {                  throw ex;              }              catch (Throwable ex) {                  throw new BeanDefinitionStoreException(                          "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);              }          }            processDeferredImportSelectors();      }

这里又是分了三种情况去解析,第一种从名字可以看出来注解的那种解析,第二种是AbstractBeanDefinition这是对XML配置方式的解析,很明显我们看第一种,继续查看源码:

    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {          processConfigurationClass(new ConfigurationClass(metadata, beanName));      }

继续查看:

    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {          if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {              return;          }            ConfigurationClass existingClass =this.configurationClasses.get(configClass);          if (existingClass != null) {              if (configClass.isImported()) {                  if (existingClass.isImported()) {                      existingClass.mergeImportedBy(configClass);                  }                  // Otherwise ignore new imported config class; existing non-imported class overrides it.                  return;              }              else {                  // Explicit bean definition found, probably replacing an import.                  // Let's remove the old one and go with the new one.                  this.configurationClasses.remove(configClass);                  for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {                      if (configClass.equals(it.next())) {                          it.remove();                      }                  }              }          }            // Recursively process the configuration class and its superclass hierarchy.          SourceClass sourceClass = asSourceClass(configClass);          do {              sourceClass = doProcessConfigurationClass(configClass, sourceClass);          }          while (sourceClass != null);            this.configurationClasses.put(configClass, configClass);      }

我们看Spring源码会发现,Spring源码里真正干活的都是doXXX方法,会发现这里终于也发现一个了,

前面是对配置类的一个判断处理,后面就是doProcessConfigurationClass真正处理了,处理完之后加入到configurationClasses中,也就是最后一句话。我们查看源码:

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)              throws IOException {            // Recursively process any member (nested) classes first          processMemberClasses(configClass, sourceClass);            // Process any @PropertySource annotations          for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(                  sourceClass.getMetadata(), PropertySources.class,                  org.springframework.context.annotation.PropertySource.class)) {              if (this.environment instanceof ConfigurableEnvironment) {                  processPropertySource(propertySource);              }              else {                  logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +                          "]. Reason: Environment must implement ConfigurableEnvironment");              }          }            // Process any @ComponentScan annotations          Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(                  sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);          if (!componentScans.isEmpty() &&                  !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {              for (AnnotationAttributes componentScan : componentScans) {                  // The config class is annotated with @ComponentScan -> perform the scan immediately                  Set<BeanDefinitionHolder> scannedBeanDefinitions =                          this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());                  // Check the set of scanned definitions for any further config classes and parse recursively if needed                  for (BeanDefinitionHolder holder : scannedBeanDefinitions) {                      if (ConfigurationClassUtils.checkConfigurationClassCandidate(                              holder.getBeanDefinition(), this.metadataReaderFactory)) {                          parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());                      }                  }              }          }            // Process any @Import annotations          processImports(configClass, sourceClass, getImports(sourceClass), true);            // Process any @ImportResource annotations          if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {              AnnotationAttributes importResource =                      AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);              String[] resources = importResource.getStringArray("locations");              Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");              for (String resource : resources) {                  String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);                  configClass.addImportedResource(resolvedResource, readerClass);              }          }            // Process individual @Bean methods          Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);          for (MethodMetadata methodMetadata : beanMethods) {              configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));          }            // Process default methods on interfaces          processInterfaces(configClass, sourceClass);            // Process superclass, if any          if (sourceClass.getMetadata().hasSuperClass()) {              String superclass = sourceClass.getMetadata().getSuperClassName();              if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {                  this.knownSuperclasses.put(superclass, configClass);                  // Superclass found, return its annotation metadata and recurse                  return sourceClass.getSuperClass();              }          }            // No superclass -> processing is complete          return null;      }

到了这里有种终见神龙真身的感觉。。。终于开始对我们常用的那些注解分别进行解析了。。我们可以挑几个最常用的看看,来看看非常常用的@ComponentScan注解吧!

IOC三大常用springbean配置用法,还有个是通过@ComponentScan配置的,SpringBoot也是通过这种。

@Target({ElementType.TYPE})  @Retention(RetentionPolicy.RUNTIME)  @Documented  @Inherited  @SpringBootConfiguration  @EnableAutoConfiguration  @ComponentScan(      excludeFilters = {@Filter(      type = FilterType.CUSTOM,      classes = {TypeExcludeFilter.class}  ), @Filter(      type = FilterType.CUSTOM,      classes = {AutoConfigurationExcludeFilter.class}  )}  )  public @interface SpringBootApplication {          ....  }

@ComponentScan源码

        // Process any @ComponentScan annotations          Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(                  sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);          if (!componentScans.isEmpty() &&                  !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {              for (AnnotationAttributes componentScan : componentScans) {                  // The config class is annotated with @ComponentScan -> perform the scan immediately                  Set<BeanDefinitionHolder> scannedBeanDefinitions =                          this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());                  // Check the set of scanned definitions for any further config classes and parse recursively if needed                  for (BeanDefinitionHolder holder : scannedBeanDefinitions) {                      if (ConfigurationClassUtils.checkConfigurationClassCandidate(                              holder.getBeanDefinition(), this.metadataReaderFactory)) {                          parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());                      }                  }              }          }

这里的第一句

        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(                  sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

是把我们的配置类也就是sourceClass,获取了元数据传到这个注解工具类里去了,是把配置类里面的@ComponentScan注解解析为对象了,这样方便后面拿到注解里设置的值。

然后往后看

Set<BeanDefinitionHolder> scannedBeanDefinitions =                          this.componentScanParser.parse(componentScan,          sourceClass.getMetadata().getClassName());

就是继续解析了,查看源码:

    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {          Assert.state(this.environment != null, "Environment must not be null");          Assert.state(this.resourceLoader != null, "ResourceLoader must not be null");            ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,                  componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);            Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");          boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);          scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :                  BeanUtils.instantiateClass(generatorClass));            ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");          if (scopedProxyMode != ScopedProxyMode.DEFAULT) {              scanner.setScopedProxyMode(scopedProxyMode);          }          else {              Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");              scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));          }            scanner.setResourcePattern(componentScan.getString("resourcePattern"));            for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {              for (TypeFilter typeFilter : typeFiltersFor(filter)) {                  scanner.addIncludeFilter(typeFilter);              }          }          for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {              for (TypeFilter typeFilter : typeFiltersFor(filter)) {                  scanner.addExcludeFilter(typeFilter);              }          }            boolean lazyInit = componentScan.getBoolean("lazyInit");          if (lazyInit) {              scanner.getBeanDefinitionDefaults().setLazyInit(true);          }            Set<String> basePackages = new LinkedHashSet<String>();          String[] basePackagesArray = componentScan.getStringArray("basePackages");          for (String pkg : basePackagesArray) {              String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),                      ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);              basePackages.addAll(Arrays.asList(tokenized));          }          for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {              basePackages.add(ClassUtils.getPackageName(clazz));          }          if (basePackages.isEmpty()) {              basePackages.add(ClassUtils.getPackageName(declaringClass));          }            scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {              @Override              protected boolean matchClassName(String className) {                  return declaringClass.equals(className);              }          });          return scanner.doScan(StringUtils.toStringArray(basePackages));      }

又是一堆代码…总体看下来会发现,前面95%都是给下面这句话设置参数:

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

很明显ClassPathBeanDefinitionScanner是真正用来扫描类的,类注释写了“A bean definition scanner that detects bean candidates on the classpath”,后面都是给扫描器设置各种名字生成器、scope、resourcePattern、以及include和exclude和是否懒加载,直到下面这段时候才开始注意路径:

        Set<String> basePackages = new LinkedHashSet<String>();          String[] basePackagesArray = componentScan.getStringArray("basePackages");          for (String pkg : basePackagesArray) {              String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),                      ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);              basePackages.addAll(Arrays.asList(tokenized));          }          for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {              basePackages.add(ClassUtils.getPackageName(clazz));          }          if (basePackages.isEmpty()) {              basePackages.add(ClassUtils.getPackageName(declaringClass));          }

获取我们在注解里写的basePackages,进行环境路径设置,最后加到之前创建的hashset类型的basePackages变量里去。然后设置排除filter到扫描器。最后一句又到了核心代码了。

        return scanner.doScan(StringUtils.toStringArray(basePackages));

这里就是最后真正扫描了,查看源码:

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {          Assert.notEmpty(basePackages, "At least one base package must be specified");          Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();          for (String basePackage : basePackages) {              Set<BeanDefinition> candidates = findCandidateComponents(basePackage);              for (BeanDefinition candidate : candidates) {                  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);                  candidate.setScope(scopeMetadata.getScopeName());                  String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);                  if (candidate instanceof AbstractBeanDefinition) {                      postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);                  }                  if (candidate instanceof AnnotatedBeanDefinition) {                      AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);                  }                  if (checkCandidate(beanName, candidate)) {                      BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);                      definitionHolder =                              AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);                      beanDefinitions.add(definitionHolder);                      registerBeanDefinition(definitionHolder, this.registry);                  }              }          }          return beanDefinitions;      }

for循环遍历basePackages,再通过findCandidateComponents方法拿到每个basePageage下的类BeanDefinition们,后面就是给每个BeanDefinition进行配置。

那我们就先来看看findCandidateComponents方法源码是怎么把这些BeanDefinition搞出来的:

    public Set<BeanDefinition> findCandidateComponents(String basePackage) {          Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();          try {              String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +                      resolveBasePackage(basePackage) + '/' + this.resourcePattern;              Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);              boolean traceEnabled = logger.isTraceEnabled();              boolean debugEnabled = logger.isDebugEnabled();              for (Resource resource : resources) {                  if (traceEnabled) {                      logger.trace("Scanning " + resource);                  }                  if (resource.isReadable()) {                      try {                          MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);                          if (isCandidateComponent(metadataReader)) {                              ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);                              sbd.setResource(resource);                              sbd.setSource(resource);                              if (isCandidateComponent(sbd)) {                                  if (debugEnabled) {                                      logger.debug("Identified candidate component class: " + resource);                                  }                                  candidates.add(sbd);                              }                              else {                                  if (debugEnabled) {                                      logger.debug("Ignored because not a concrete top-level class: " + resource);                                  }                              }                          }                          else {                              if (traceEnabled) {                                  logger.trace("Ignored because not matching any filter: " + resource);                              }                          }                      }                      catch (Throwable ex) {                          throw new BeanDefinitionStoreException(                                  "Failed to read candidate component class: " + resource, ex);                      }                  }                  else {                      if (traceEnabled) {                          logger.trace("Ignored because not readable: " + resource);                      }                  }              }          }          catch (IOException ex) {              throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);          }          return candidates;      }

这里的办法就比较好懂了,可能有些自己平时都写过。第一个明显拼字符串,拼最终要读取的资源文件路径,然后把文件路径交给resourcePatternResolver,获取一个Resource类(继承自InputStreamSource),这个就是个IO流读取。

这里大段都是try catch了,因为涉及到很多失败的情况,都做了处理。

里面主要还做了filter的判断,判断是不是你是不是exclude了一些 这样就不读了,然后读出来是不是打了Component注解的,最后条件都满足的话就把读出来的信息就加到 最终的一个LinkedHashSet的集合里去了,进行返回。

全读出来之后,返回上层doScan方法的这里:

Set<BeanDefinition> candidates = findCandidateComponents(basePackage);              for (BeanDefinition candidate : candidates) {                  ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);                  candidate.setScope(scopeMetadata.getScopeName());                  String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);                  if (candidate instanceof AbstractBeanDefinition) {                      postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);                  }                  if (candidate instanceof AnnotatedBeanDefinition) {                      AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);                  }                  if (checkCandidate(beanName, candidate)) {                      BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);                      definitionHolder =                              AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);                      beanDefinitions.add(definitionHolder);                      registerBeanDefinition(definitionHolder, this.registry);                  }              }

给扫描出来的BeanDefinition设置scope,单例多例、搞一个名字给这个BeanDefinition,以及判断是注解形式配置的还是XML形式配置的给它设置一些默认的配置,比如默认的懒加载设置各种,spring有默认的或者读你设置的。最后把这个BeanDefinition和名字一起包装成BeanDefinitionHolder,通过:

BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);  definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata,definitionHolder, this.registry);  beanDefinitions.add(definitionHolder);  registerBeanDefinition(definitionHolder, this.registry);

最后registerBeanDefinition注册到容器里去。说实话我又好奇是咋注册的,不断打开源码:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)              throws BeanDefinitionStoreException {            Assert.hasText(beanName, "Bean name must not be empty");          Assert.notNull(beanDefinition, "BeanDefinition must not be null");            if (beanDefinition instanceof AbstractBeanDefinition) {              try {                  ((AbstractBeanDefinition) beanDefinition).validate();              }              catch (BeanDefinitionValidationException ex) {                  throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                          "Validation of bean definition failed", ex);              }          }            BeanDefinition oldBeanDefinition;            oldBeanDefinition = this.beanDefinitionMap.get(beanName);          if (oldBeanDefinition != null) {              if (!isAllowBeanDefinitionOverriding()) {                  throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,                          "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +                          "': There is already [" + oldBeanDefinition + "] bound.");              }              else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {                  // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE                  if (this.logger.isWarnEnabled()) {                      this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +                              "' with a framework-generated bean definition: replacing [" +                              oldBeanDefinition + "] with [" + beanDefinition + "]");                  }              }              else if (!beanDefinition.equals(oldBeanDefinition)) {                  if (this.logger.isInfoEnabled()) {                      this.logger.info("Overriding bean definition for bean '" + beanName +                              "' with a different definition: replacing [" + oldBeanDefinition +                              "] with [" + beanDefinition + "]");                  }              }              else {                  if (this.logger.isDebugEnabled()) {                      this.logger.debug("Overriding bean definition for bean '" + beanName +                              "' with an equivalent definition: replacing [" + oldBeanDefinition +                              "] with [" + beanDefinition + "]");                  }              }              this.beanDefinitionMap.put(beanName, beanDefinition);          }          else {              if (hasBeanCreationStarted()) {                  // Cannot modify startup-time collection elements anymore (for stable iteration)                  synchronized (this.beanDefinitionMap) {                      this.beanDefinitionMap.put(beanName, beanDefinition);                      List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);                      updatedDefinitions.addAll(this.beanDefinitionNames);                      updatedDefinitions.add(beanName);                      this.beanDefinitionNames = updatedDefinitions;                      if (this.manualSingletonNames.contains(beanName)) {                          Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);                          updatedSingletons.remove(beanName);                          this.manualSingletonNames = updatedSingletons;                      }                  }              }              else {                  // Still in startup registration phase                  this.beanDefinitionMap.put(beanName, beanDefinition);                  this.beanDefinitionNames.add(beanName);                  this.manualSingletonNames.remove(beanName);              }              this.frozenBeanDefinitionNames = null;          }            if (oldBeanDefinition != null || containsSingleton(beanName)) {              resetBeanDefinition(beanName);          }      }

啰嗦了很长一大段,其实是一些校验、对同名BeanDefinition的处理啥的,核心就一句:

this.beanDefinitionMap.put(beanName, beanDefinition);

查看这个beanDefinitionMap

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

就是个ConcurrentHashMap,在DefaultListableBeanFactory类里的一个private私有成员变量,所以也可见DefaultListableBeanFactory类的重要性,BeanDefinition都存在它这了,容器。

ok,一探到底了,开始回到上层调用吧。

回到之前的ConfigurationClassParser类的doProcessConfigurationClass方法中,是这个方法里开始的各种注解的解析:

        // Process any @ComponentScan annotations          Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(                  sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);          if (!componentScans.isEmpty() &&                  !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {              for (AnnotationAttributes componentScan : componentScans) {                  // The config class is annotated with @ComponentScan -> perform the scan immediately                  Set<BeanDefinitionHolder> scannedBeanDefinitions =                          this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());                  // Check the set of scanned definitions for any further config classes and parse recursively if needed                  for (BeanDefinitionHolder holder : scannedBeanDefinitions) {                      if (ConfigurationClassUtils.checkConfigurationClassCandidate(                              holder.getBeanDefinition(), this.metadataReaderFactory)) {                          parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());                      }                  }              }          }

我们之前是对这里的:

Set<BeanDefinitionHolder> scannedBeanDefinitions =                          this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

进行的不断深挖,那就往下看吧:

for (BeanDefinitionHolder holder : scannedBeanDefinitions) {      if (ConfigurationClassUtils.checkConfigurationClassCandidate(          holder.getBeanDefinition(), this.metadataReaderFactory)) {          parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());      }  }

这里是检查ComponentScan扫出来的类是不是又打了ComonentScan注解,可能就需要递归解析了。

OK,那我们就把@ComponentScan相关源码分析完了。

这个方法里还有别的注解的解析。比如我们这个系列最开始给的例子:通过Java配置类配置bean 就是用的@Bean注解。那我们来看看@Bean注解。

@Bean源码

// Process individual @Bean methods  Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);  for (MethodMetadata methodMetadata : beanMethods) {      configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));  }

这里面这个addBeanMethod方法打开一看:

    public void addBeanMethod(BeanMethod method) {          this.beanMethods.add(method);      }

而beanMehtods是个private final Set beanMethods = new LinkedHashSet();

感觉是啥也没干,就是加进去了而已。只能看看retrieveBeanMethodMetadata是在干嘛了,打开:

    private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {          AnnotationMetadata original = sourceClass.getMetadata();          Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());          if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {              // Try reading the class file via ASM for deterministic declaration order...              // Unfortunately, the JVM's standard reflection returns methods in arbitrary              // order, even between different runs of the same application on the same JVM.              try {                  AnnotationMetadata asm =                          this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();                  Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());                  if (asmMethods.size() >= beanMethods.size()) {                      Set<MethodMetadata> selectedMethods = new LinkedHashSet<MethodMetadata>(asmMethods.size());                      for (MethodMetadata asmMethod : asmMethods) {                          for (MethodMetadata beanMethod : beanMethods) {                              if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {                                  selectedMethods.add(beanMethod);                                  break;                              }                          }                      }                      if (selectedMethods.size() == beanMethods.size()) {                          // All reflection-detected methods found in ASM method set -> proceed                          beanMethods = selectedMethods;                      }                  }              }              catch (IOException ex) {                  logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);                  // No worries, let's continue with the reflection metadata we started with...              }          }          return beanMethods;      }

这里貌似也没干啥,就是把配置类里面的打了bean注解的方法返回拿出来了,啥也没干。那么这个@Bean注解标注里的创建对象到底在哪里创建并加到容器呢?

这里明显就是个预操作,那么真正的操作在上层调用后面(实际上这个parse解析方法里也就只有@ComponentScan的真正处理了),我们返回上层直到有parse方法的地方:来到ConfigurationClassPostProcessor的processConfigBeanDefinitions方法:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {          List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();          String[] candidateNames = registry.getBeanDefinitionNames();            for (String beanName : candidateNames) {              BeanDefinition beanDef = registry.getBeanDefinition(beanName);              if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||                      ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {                  if (logger.isDebugEnabled()) {                      logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);                  }              }              else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {                  configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));              }          }            // Return immediately if no @Configuration classes were found          if (configCandidates.isEmpty()) {              return;          }            // Sort by previously determined @Order value, if applicable          Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {              @Override              public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {                  int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());                  int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());                  return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;              }          });            // Detect any custom bean name generation strategy supplied through the enclosing application context          SingletonBeanRegistry sbr = null;          if (registry instanceof SingletonBeanRegistry) {              sbr = (SingletonBeanRegistry) registry;              if (!this.localBeanNameGeneratorSet && sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {                  BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);                  this.componentScanBeanNameGenerator = generator;                  this.importBeanNameGenerator = generator;              }          }            // Parse each @Configuration class          ConfigurationClassParser parser = new ConfigurationClassParser(                  this.metadataReaderFactory, this.problemReporter, this.environment,                  this.resourceLoader, this.componentScanBeanNameGenerator, registry);            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);          Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());          do {              parser.parse(candidates);              parser.validate();                Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());              configClasses.removeAll(alreadyParsed);                // Read the model and create bean definitions based on its content              if (this.reader == null) {                  this.reader = new ConfigurationClassBeanDefinitionReader(                          registry, this.sourceExtractor, this.resourceLoader, this.environment,                          this.importBeanNameGenerator, parser.getImportRegistry());              }              this.reader.loadBeanDefinitions(configClasses);              alreadyParsed.addAll(configClasses);                candidates.clear();              if (registry.getBeanDefinitionCount() > candidateNames.length) {                  String[] newCandidateNames = registry.getBeanDefinitionNames();                  Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));                  Set<String> alreadyParsedClasses = new HashSet<String>();                  for (ConfigurationClass configurationClass : alreadyParsed) {                      alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());                  }                  for (String candidateName : newCandidateNames) {                      if (!oldCandidateNames.contains(candidateName)) {                          BeanDefinition bd = registry.getBeanDefinition(candidateName);                          if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&                                  !alreadyParsedClasses.contains(bd.getBeanClassName())) {                              candidates.add(new BeanDefinitionHolder(bd, candidateName));                          }                      }                  }                  candidateNames = newCandidateNames;              }          }          while (!candidates.isEmpty());            // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes          if (sbr != null) {              if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {                  sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());              }          }            if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {              ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();          }      }

我们只看我们之前查看源代码的parse方法那附近和后面就行了,有个do while循环解析那:

do {              parser.parse(candidates);              parser.validate();                Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());              configClasses.removeAll(alreadyParsed);                // Read the model and create bean definitions based on its content              if (this.reader == null) {                  this.reader = new ConfigurationClassBeanDefinitionReader(                          registry, this.sourceExtractor, this.resourceLoader, this.environment,                          this.importBeanNameGenerator, parser.getImportRegistry());              }              this.reader.loadBeanDefinitions(configClasses);              alreadyParsed.addAll(configClasses);                candidates.clear();              if (registry.getBeanDefinitionCount() > candidateNames.length) {                  String[] newCandidateNames = registry.getBeanDefinitionNames();                  Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));                  Set<String> alreadyParsedClasses = new HashSet<String>();                  for (ConfigurationClass configurationClass : alreadyParsed) {                      alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());                  }                  for (String candidateName : newCandidateNames) {                      if (!oldCandidateNames.contains(candidateName)) {                          BeanDefinition bd = registry.getBeanDefinition(candidateName);                          if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&                                  !alreadyParsedClasses.contains(bd.getBeanClassName())) {                              candidates.add(new BeanDefinitionHolder(bd, candidateName));                          }                      }                  }                  candidateNames = newCandidateNames;              }          }          while (!candidates.isEmpty());

parser.parse(candidates);后面是校验和创建配置类的Set。注意到有一个方法:

this.reader.loadBeanDefinitions(configClasses);

这个操作reader的loadBeanDefinitions比较贴近意思了,点进去看看:

    /**       * 读取 {@code configurationModel}, 根据其内容在registry中注册bean定义.       */      public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {          TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();          for (ConfigurationClass configClass : configurationModel) {              loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);          }      }

这个注释提示得非常明显,继续跟进loadBeanDefinitionsForConfigurationClass:

    /**       * Read a particular {@link ConfigurationClass}, registering bean definitions       * for the class itself and all of its {@link Bean} methods.       */      private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,              TrackedConditionEvaluator trackedConditionEvaluator) {            if (trackedConditionEvaluator.shouldSkip(configClass)) {              String beanName = configClass.getBeanName();              if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {                  this.registry.removeBeanDefinition(beanName);              }              this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());              return;          }            if (configClass.isImported()) {              registerBeanDefinitionForImportedConfigurationClass(configClass);          }          for (BeanMethod beanMethod : configClass.getBeanMethods()) {              loadBeanDefinitionsForBeanMethod(beanMethod);          }          loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());          loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());      }

注意到里面有个重点啊:

        for (BeanMethod beanMethod : configClass.getBeanMethods()) {              loadBeanDefinitionsForBeanMethod(beanMethod);          }

这也太明显了哈,把配置的bean方法拿出来,一个个去加载,继续跟进:

    /**       * Read the given {@link BeanMethod}, registering bean definitions       * with the BeanDefinitionRegistry based on its contents.       */      private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {          ConfigurationClass configClass = beanMethod.getConfigurationClass();          MethodMetadata metadata = beanMethod.getMetadata();          String methodName = metadata.getMethodName();            // Do we need to mark the bean as skipped by its condition?          if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {              configClass.skippedBeanMethods.add(methodName);              return;          }          if (configClass.skippedBeanMethods.contains(methodName)) {              return;          }            // Consider name and any aliases          AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);          List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));          String beanName = (!names.isEmpty() ? names.remove(0) : methodName);            // Register aliases even when overridden          for (String alias : names) {              this.registry.registerAlias(beanName, alias);          }            // Has this effectively been overridden before (e.g. via XML)?          if (isOverriddenByExistingDefinition(beanMethod, beanName)) {              return;          }            ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);          beanDef.setResource(configClass.getResource());          beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));            if (metadata.isStatic()) {              // static @Bean method              beanDef.setBeanClassName(configClass.getMetadata().getClassName());              beanDef.setFactoryMethodName(methodName);          }          else {              // instance @Bean method              beanDef.setFactoryBeanName(configClass.getBeanName());              beanDef.setUniqueFactoryMethodName(methodName);          }          beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);          beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);            AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);            Autowire autowire = bean.getEnum("autowire");          if (autowire.isAutowire()) {              beanDef.setAutowireMode(autowire.value());          }            String initMethodName = bean.getString("initMethod");          if (StringUtils.hasText(initMethodName)) {              beanDef.setInitMethodName(initMethodName);          }            String destroyMethodName = bean.getString("destroyMethod");          if (destroyMethodName != null) {              beanDef.setDestroyMethodName(destroyMethodName);          }            // Consider scoping          ScopedProxyMode proxyMode = ScopedProxyMode.NO;          AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);          if (attributes != null) {              beanDef.setScope(attributes.getString("value"));              proxyMode = attributes.getEnum("proxyMode");              if (proxyMode == ScopedProxyMode.DEFAULT) {                  proxyMode = ScopedProxyMode.NO;              }          }            // Replace the original bean definition with the target one, if necessary          BeanDefinition beanDefToRegister = beanDef;          if (proxyMode != ScopedProxyMode.NO) {              BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(                      new BeanDefinitionHolder(beanDef, beanName), this.registry,                      proxyMode == ScopedProxyMode.TARGET_CLASS);              beanDefToRegister = new ConfigurationClassBeanDefinition(                      (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);          }            if (logger.isDebugEnabled()) {              logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",                      configClass.getMetadata().getClassName(), beanName));          }            this.registry.registerBeanDefinition(beanName, beanDefToRegister);      }

通过方法注释更加确定了,最后一句代码正是容器注册代码。

我们大致来看看,前三句是把配置类拿出来、拿方法数据、方法名。后面两个判断是要看看要不要跳过,跳过就直接return了,不注册。再往后是把@Bean注解里的name对应的值拿出来,也就是别名拿出来并注册,后面也是各种把@Bean注解里的东西取出来操作,autowire模型(通过id还是name?)、initMethod、destroyMethod,各种细节配置就不多说了。最后通过this.registry.registerBeanDefinition就注册进去了

值得注意的是beanName来自里面的:

List<String> names = new ArrayList<String(Arrays.asList(bean.getStringArray("name")));  String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

也就是你的@Bean注解里面没有写name的时候,实际上默认就是拿方法名做beanName了!

至此,@Bean注解也分析完毕.

至此ioc构造器的三大方法中的refresh(),里的invokeBeanFactoryPostProcessors的部分就讲完了,剩下的下篇文章继续分析。