这是春节后的第一篇博客,我在构思这篇博客的时候,一度想放弃,想想要不要换个东西写,因为毕竟个人水平有限,Spring 源码实在博大精深,不是我这个菜的抠脚的菜鸡可以驾驭的,怕误人子弟,还有就是源码分析类的博客实在是太难写了,和一般的博客真心不同,可能写了很多,自己都不知道自己在写些什么,但是还是要坚持,从接触博客的那一天开始,就非常佩服那些大神,乐于分享,无私奉献,我也从那些博客中学到了不少东西,慢慢的从一个嫩嫩的小菜鸡变成了秃头大菜鸡,其中最佩服的就是那些源码分析类的博客,虽然看不懂,但是从博客中,我分明读出了大神们对技术的热爱,对技术的坚持,对技术的执著。坚持!
更多精彩内容请看 web 前端中文站
http://www.lisa33xiaoq.net 可按 Ctrl + D 进行收藏
在上一篇 Spring 源码解析中,我们分析了
//根据参数类型可以知道,其实可以传入多个 annotatedClasses,但是这种情况出现的比较少 public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { //调用无参构造函数,会先调用父类 GenericApplicationContext 的构造函数 //父类的构造函数里面就是初始化 DefaultListableBeanFactory,并且赋值给 beanFactory //本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器 ClassPathBeanDefinitionScanner scanner //scanner 的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到 scanner 对象的 this(); //把传入的类进行注册,这里有两个情况, //传入传统的配置类 //传入 bean(虽然一般没有人会这么做 //看到后面会知道 spring 把传统的带上@Configuration 的配置类称之为 FULL 配置类,不带@Configuration 的称之为 Lite 配置类 //但是我们这里先把带上@Configuration 的配置类称之为传统配置类,不带的称之为普通 bean register(annotatedClasses); //刷新 refresh(); }
中的前两行代码,回顾下,这两行代码,主要是把我们的配置类和内置的几个后置处理器放到了两个集合中:
//beanDefinitionMap 是 Map<String, BeanDefinition>, //这里就是把 beanName 作为 key,beanDefinition 作为 value,推到 map 里面 this.beanDefinitionMap.put(beanName, beanDefinition); //beanDefinitionNames 就是一个 List<String>,这里就是把 beanName 放到 List 中去 this.beanDefinitionNames.add(beanName);
今天,我们来分析下第三行代码,即:
//刷新 refresh();
这个方法做了很多事情,让我们点开这个方法:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //刷新预处理,和主流程关系不大,就是保存了容器的启动时间,启动标志等 prepareRefresh(); //DefaultListableBeanFactory // Tell the subclass to refresh the internal bean factory. //和主流程关系也不大,最终获得了 DefaultListableBeanFactory, // DefaultListableBeanFactory 实现了 ConfigurableListableBeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //还是一些准备工作,添加了两个后置处理器:ApplicationContextAwareProcessor,ApplicationListenerDetector //还设置了 忽略自动装配 和 允许自动装配 的接口,如果不存在某个 bean 的时候,spring 就自动注册 singleton bean //还设置了 bean 表达式解析器 等 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //这是一个空方法 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //执行自定义的 BeanFactoryProcessor 和内置的 BeanFactoryProcessor invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注册 BeanPostProcessor 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(); } } }
里面有很多小方法,我们今天的目标是分析前五个小方法:
prepareRefresh
从命名来看,就知道这个方法主要做了一些刷新前的准备工作,和主流程关系不大,主要是保存了容器的启动时间,启动标志等。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
这个方法和主流程关系也不是很大,可以简单的认为,就是把 beanFactory 取出来而已。
prepareBeanFactory
//还是一些准备工作,添加了两个后置处理器:ApplicationContextAwareProcessor,ApplicationListenerDetector //还设置了 忽略自动装配 和 允许自动装配 的接口,如果不存在某个 bean 的时候,spring 就自动注册 singleton bean //还设置了 bean 表达式解析器 等 prepareBeanFactory(beanFactory);
这代码相比前面两个就比较重要了,我们需要点进去好好看看,做了什么操作:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader());//设置类加载器 //设置 bean 表达式解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //属性编辑器支持 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. //添加一个后置处理器:ApplicationContextAwareProcessor,此后置处理处理器实现了 BeanPostProcessor 接口 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //以下接口,忽略自动装配 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. //以下接口,允许自动装配,第一个参数是自动装配的类型,,第二个字段是自动装配的值 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. //添加一个后置处理器:ApplicationListenerDetector,此后置处理器实现了 BeanPostProcessor 接口 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } //如果没有注册过 bean 名称为 XXX,spring 就自己创建一个名称为 XXX 的 singleton bean //Register default environment beans. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
主要做了如下的操作:
- 设置了一个类加载器
- 设置了 bean 表达式解析器
- 添加了属性编辑器的支持
- 添加了一个后置处理器:ApplicationContextAwareProcessor,此后置处理器实现了 BeanPostProcessor 接口
- 设置了一些忽略自动装配的接口
- 设置了一些允许自动装配的接口,并且进行了赋值操作
- 在容器中还没有 XX 的 bean 的时候,帮我们注册 beanName 为 XX 的 singleton bean
postProcessBeanFactory(beanFactory)
//这是一个空方法 postProcessBeanFactory(beanFactory);
这是一个空方法,可能以后 Spring 会进行扩展把。
invokeBeanFactoryPostProcessors(beanFactory)
//执行自定义的 BeanFactoryProcessor 和内置的 BeanFactoryProcessor invokeBeanFactoryPostProcessors(beanFactory);
重点代码终于来了,可以说 这句代码是目前为止最重要,也是内容最多的代码了,我们有必要好好分析下:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { //getBeanFactoryPostProcessors 真是坑,第一次看到这里的时候,愣住了,总觉得获得的永远都是空的集合,掉入坑里,久久无法自拔 //后来才知道 spring 允许我们手动添加 BeanFactoryPostProcessor //即:annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX); 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())); } }
让我们看看第一个小方法的第二个参数:
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() { return this.beanFactoryPostProcessors; }
这里获得的是 BeanFactoryPostProcessor,当我看到这里的时候,愣住了,通过 IDEA 的查找引用功能,我发现这个集合永远都是空的,根本没有代码为这个集合添加数据,很久都没有想通,后来才知道我们在外部可以手动添加一个后置处理器,而不是交给 Spring 去扫描,即:
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class); annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX);
只有这样,这个集合才不会为空,但是应该没有很少会有人这么做吧,当然也有可能是我孤陋寡闻。
让我们点开 invokeBeanFactoryPostProcessors 方法:
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<>(); //beanFactory 是 DefaultListableBeanFactory,是 BeanDefinitionRegistry 的实现类,所以肯定满足 if if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; //regularPostProcessors 用来存放 BeanFactoryPostProcessor, List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>(); //registryProcessors 用来存放 BeanDefinitionRegistryPostProcessor //BeanDefinitionRegistryPostProcessor 扩展了 BeanFactoryPostProcessor List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>(); // 循环传进来的 beanFactoryPostProcessors,正常情况下,beanFactoryPostProcessors 肯定没有数据 // 因为 beanFactoryPostProcessors 是获得手动添加的,而不是 spring 扫描的 // 只有手动调用 annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX)才会有数据 for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { // 判断 postProcessor 是不是 BeanDefinitionRegistryPostProcessor,因为 BeanDefinitionRegistryPostProcessor // 扩展了 BeanFactoryPostProcessor,所以这里先要判断是不是 BeanDefinitionRegistryPostProcessor // 是的话,直接执行 postProcessBeanDefinitionRegistry 方法,然后把对象装到 registryProcessors 里面去 if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else {//不是的话,就装到 regularPostProcessors 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. //一个临时变量,用来装载 BeanDefinitionRegistryPostProcessor //BeanDefinitionRegistry 继承了 PostProcessorBeanFactoryPostProcessor List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. // 获得实现 BeanDefinitionRegistryPostProcessor 接口的类的 BeanName:org.springframework.context.annotation.internalConfigurationAnnotationProcessor // 并且装入数组 postProcessorNames,我理解一般情况下,只会找到一个 // 这里又有一个坑,为什么我自己创建了一个实现 BeanDefinitionRegistryPostProcessor 接口的类,也打上了@Component 注解 // 配置类也加上了@Component 注解,但是这里却没有拿到 // 因为直到这一步,Spring 还没有去扫描,扫描是在 ConfigurationClassPostProcessor 类中完成的,也就是下面的第一个 // invokeBeanDefinitionRegistryPostProcessors 方法 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //获得 ConfigurationClassPostProcessor 类,并且放到 currentRegistryProcessors //ConfigurationClassPostProcessor 是很重要的一个类,它实现了 BeanDefinitionRegistryPostProcessor 接口 //BeanDefinitionRegistryPostProcessor 接口又实现了 BeanFactoryPostProcessor 接口 //ConfigurationClassPostProcessor 是极其重要的类 //里面执行了扫描 Bean,Import,ImportResouce 等各种操作 //用来处理配置类(有两种情况 一种是传统意义上的配置类,一种是普通的 bean)的各种逻辑 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); //把 name 放到 processedBeans,后续会根据这个集合来判断处理器是否已经被执行过了 processedBeans.add(ppName); } } //处理排序 sortPostProcessors(currentRegistryProcessors, beanFactory); //合并 Processors,为什么要合并,因为 registryProcessors 是装载 BeanDefinitionRegistryPostProcessor 的 //一开始的时候,spring 只会执行 BeanDefinitionRegistryPostProcessor 独有的方法 //而不会执行 BeanDefinitionRegistryPostProcessor 父类的方法,即 BeanFactoryProcessor 的方法 //所以这里需要把处理器放入一个集合中,后续统一执行父类的方法 registryProcessors.addAll(currentRegistryProcessors); //可以理解为执行 ConfigurationClassPostProcessor 的 postProcessBeanDefinitionRegistry 方法 //Spring 热插播的体现,像 ConfigurationClassPostProcessor 就相当于一个组件,Spring 很多事情就是交给组件去管理 //如果不想用这个组件,直接把注册组件的那一步去掉就可以 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //因为 currentRegistryProcessors 是一个临时变量,所以需要清除 currentRegistryProcessors.clear(); // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered. // 再次根据 BeanDefinitionRegistryPostProcessor 获得 BeanName,看这个 BeanName 是否已经被执行过了,有没有实现 Ordered 接口 // 如果没有被执行过,也实现了 Ordered 接口的话,把对象推送到 currentRegistryProcessors,名称推送到 processedBeans // 如果没有实现 Ordered 接口的话,这里不把数据加到 currentRegistryProcessors,processedBeans 中,后续再做处理 // 这里才可以获得我们定义的实现了 BeanDefinitionRegistryPostProcessor 的 Bean postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } //处理排序 sortPostProcessors(currentRegistryProcessors, beanFactory); //合并 Processors registryProcessors.addAll(currentRegistryProcessors); //执行我们自定义的 BeanDefinitionRegistryPostProcessor invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); //清空临时变量 currentRegistryProcessors.clear(); // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear. // 上面的代码是执行了实现了 Ordered 接口的 BeanDefinitionRegistryPostProcessor, // 下面的代码就是执行没有实现 Ordered 接口的 BeanDefinitionRegistryPostProcessor boolean reiterate = true; while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } // Now, invoke the postProcessBeanFactory callback of all processors handled so far. //registryProcessors 集合装载 BeanDefinitionRegistryPostProcessor //上面的代码是执行子类独有的方法,这里需要再把父类的方法也执行一次 invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); //regularPostProcessors 装载 BeanFactoryPostProcessor,执行 BeanFactoryPostProcessor 的方法 //但是 regularPostProcessors 一般情况下,是不会有数据的,只有在外面手动添加 BeanFactoryPostProcessor,才会有数据 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! //找到 BeanFactoryPostProcessor 实现类的 BeanName 数组 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // Separate between BeanFactoryPostProcessors that implement PriorityOrdered, // Ordered, and the rest. List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); //循环 BeanName 数组 for (String ppName : postProcessorNames) { //如果这个 Bean 被执行过了,跳过 if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } //如果实现了 PriorityOrdered 接口,加入到 priorityOrderedPostProcessors else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } //如果实现了 Ordered 接口,加入到 orderedPostProcessorNames else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } //如果既没有实现 PriorityOrdered,也没有实现 Ordered。加入到 nonOrderedPostProcessorNames else { nonOrderedPostProcessorNames.add(ppName); } } //排序处理 priorityOrderedPostProcessors,即实现了 PriorityOrdered 接口的 BeanFactoryPostProcessor // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. sortPostProcessors(priorityOrderedPostProcessors, beanFactory); //执行 priorityOrderedPostProcessors invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); //执行实现了 Ordered 接口的 BeanFactoryPostProcessor // Next, invoke the BeanFactoryPostProcessors that implement Ordered. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // 执行既没有实现 PriorityOrdered 接口,也没有实现 Ordered 接口的 BeanFactoryPostProcessor // Finally, invoke all other BeanFactoryPostProcessors. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(); 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(); }
首先判断 beanFactory 是不是 BeanDefinitionRegistry 的实例,当然肯定是的,然后执行如下操作:
-
定义了一个 Set,装载 BeanName,后面会根据这个 Set,来判断后置处理器是否被执行过了。
-
定义了两个 List,一个是 regularPostProcessors,用来装载 BeanFactoryPostProcessor,一个是 registryProcessors 用来装载 BeanDefinitionRegistryPostProcessor,其中 BeanDefinitionRegistryPostProcessor 扩展了 BeanFactoryPostProcessor。BeanDefinitionRegistryPostProcessor 有两个方法,一个是独有的 postProcessBeanDefinitionRegistry 方法,一个是父类的 postProcessBeanFactory 方法。
-
循环传进来的 beanFactoryPostProcessors,上面已经解释过了,一般情况下,这里永远都是空的,只有手动 add beanFactoryPostProcessor,这里才会有数据。我们假设 beanFactoryPostProcessors 有数据,进入循环,判断 postProcessor 是不是 BeanDefinitionRegistryPostProcessor,因为 BeanDefinitionRegistryPostProcessor 扩展了 BeanFactoryPostProcessor,所以这里先要判断是不是 BeanDefinitionRegistryPostProcessor,是的话,执行 postProcessBeanDefinitionRegistry 方法,然后把对象装到 registryProcessors 里面去,不是的话,就装到 regularPostProcessors。
-
定义了一个临时变量:currentRegistryProcessors,用来装载 BeanDefinitionRegistryPostProcessor。
-
getBeanNamesForType,顾名思义,是根据类型查到 BeanNames,这里有一点需要注意,就是去哪里找,点开这个方法的话,就知道是循环 beanDefinitionNames 去找,这个方法以后也会经常看到。这里传了 BeanDefinitionRegistryPostProcessor.class,就是找到类型为 BeanDefinitionRegistryPostProcessor 的后置处理器,并且赋值给 postProcessorNames。一般情况下,只会找到一个,就是 org.springframework.context.annotation.internalConfigurationAnnotationProcessor,也就是 ConfigurationAnnotationProcessor。这个后置处理器在上一节中已经说明过了,十分重要。这里有一个问题,为什么我自己写了个类,实现了 BeanDefinitionRegistryPostProcessor 接口,也打上了@Component 注解,但是这里没有获得,因为直到这一步,Spring 还没有完成扫描,扫描是在 ConfigurationClassPostProcessor 类中完成的,也就是下面第一个 invokeBeanDefinitionRegistryPostProcessors 方法。
-
循环 postProcessorNames,其实也就是 org.springframework.context.annotation.internalConfigurationAnnotationProcessor,判断此后置处理器是否实现了 PriorityOrdered 接口(ConfigurationAnnotationProcessor 也实现了 PriorityOrdered 接口),
如果实现了,把它添加到 currentRegistryProcessors 这个临时变量中,再放入 processedBeans,代表这个后置处理已经被处理过了。当然现在还没有处理,但是马上就要处理了。。。 -
进行排序,PriorityOrdered 是一个排序接口,如果实现了它,就说明此后置处理器是有顺序的,所以需要排序。当然目前这里只有一个后置处理器,就是 ConfigurationClassPostProcessor。
-
把 currentRegistryProcessors 合并到 registryProcessors,为什么需要合并?因为一开始 spring 只会执行 BeanDefinitionRegistryPostProcessor 独有的方法,而不会执行 BeanDefinitionRegistryPostProcessor 父类的方法,即 BeanFactoryProcessor 接口中的方法,所以需要把这些后置处理器放入一个集合中,后续统一执行 BeanFactoryProcessor 接口中的方法。当然目前这里只有一个后置处理器,就是 ConfigurationClassPostProcessor。
-
可以理解为执行 currentRegistryProcessors 中的 ConfigurationClassPostProcessor 中的 postProcessBeanDefinitionRegistry 方法,这就是 Spring 设计思想的体现了,在这里体现的就是其中的热插拔,插件化开发的思想。Spring 中很多东西都是交给插件去处理的,这个后置处理器就相当于一个插件,如果不想用了,直接不添加就是了。这个方法特别重要,我们后面会详细说来。
-
清空 currentRegistryProcessors,因为 currentRegistryProcessors 是一个临时变量,已经完成了目前的使命,所以需要清空,当然后面还会用到。
-
再次根据 BeanDefinitionRegistryPostProcessor 获得 BeanName,然后进行循环,看这个后置处理器是否被执行过了,如果没有被执行过,也实现了 Ordered 接口的话,把此后置处理器推送到 currentRegistryProcessors 和 processedBeans 中。
这里就可以获得我们定义的,并且打上@Component 注解的后置处理器了,因为 Spring 已经完成了扫描,但是这里需要注意的是,由于 ConfigurationClassPostProcessor 在上面已经被执行过了,所以虽然可以通过 getBeanNamesForType 获得,但是并不会加入到 currentRegistryProcessors 和 processedBeans。 -
处理排序。
-
合并 Processors,合并的理由和上面是一样的。
-
执行我们自定义的 BeanDefinitionRegistryPostProcessor。
-
清空临时变量。
-
在上面的方法中,仅仅是执行了实现了 Ordered 接口的 BeanDefinitionRegistryPostProcessor,这里是执行没有实现 Ordered 接口的 BeanDefinitionRegistryPostProcessor。
-
上面的代码是执行子类独有的方法,这里需要再把父类的方法也执行一次。
-
执行 regularPostProcessors 中的后置处理器的方法,需要注意的是,在一般情况下,regularPostProcessors 是不会有数据的,只有在外面手动添加 BeanFactoryPostProcessor,才会有数据。
-
查找实现了 BeanFactoryPostProcessor 的后置处理器,并且执行后置处理器中的方法。和上面的逻辑差不多,不再详细说明。
这就是这个方法中做的主要的事情了,可以说是比较复杂的。但是逻辑还是比较清晰的,在第 9 步的时候,我说有一个方法会详细说来,现在就让我们好好看看这个方法究竟做了什么吧。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames();//获得所有的 BeanDefinition 的 Name,放入 candidateNames 数组 //循环 candidateNames 数组 for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName);//根据 beanName 获得 BeanDefinition // 内部有两个标记位来标记是否已经处理过了 // 这里会引发一连串知识盲点 // 当我们注册配置类的时候,可以不加 Configuration 注解,直接使用 Component ComponentScan Import ImportResource 注解,称之为 Lite 配置类 // 如果加了 Configuration 注解,就称之为 Full 配置类 // 如果我们注册了 Lite 配置类,我们 getBean 这个配置类,会发现它就是原本的那个配置类 // 如果我们注册了 Full 配置类,我们 getBean 这个配置类,会发现它已经不是原本那个配置类了,而是已经被 cgilb 代理的类了 // 写一个 A 类,其中有一个构造方法,打印出“你好” // 再写一个配置类,里面有两个 bean 注解的方法 // 其中一个方法 new 了 A 类,并且返回 A 的对象,把此方法称之为 getA // 第二个方法又调用了 getA 方法 // 如果配置类是 Lite 配置类,会发现打印了两次“你好”,也就是说 A 类被 new 了两次 // 如果配置类是 Full 配置类,会发现只打印了一次“你好”,也就是说 A 类只被 new 了一次,因为这个类被 cgilb 代理了,方法已经被改写 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } //判断是否为配置类(有两种情况 一种是传统意义上的配置类,一种是普通的 bean), //在这个方法内部,会做判断,这个配置类是 Full 配置类,还是 Lite 配置类,并且做上标记 //满足条件,加入到 configCandidates 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 //处理排序 configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry sbr = null; // DefaultListableBeanFactory 最终会实现 SingletonBeanRegistry 接口,所以可以进入到这个 if if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { //spring 中可以修改默认的 bean 命名方式,这里就是看用户有没有自定义 bean 命名方式,虽然一般没有人会这么做 BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); } // Parse each @Configuration class ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { //解析配置类(传统意义上的配置类或者是普通 bean,核心来了) parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<>(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);//直到这一步才把 Import 的类,@Bean @ImportRosource 转换成 BeanDefinition alreadyParsed.addAll(configClasses);//把 configClasses 加入到 alreadyParsed,代表 candidates.clear(); //获得注册器里面 BeanDefinition 的数量 和 candidateNames 进行比较 //如果大于的话,说明有新的 BeanDefinition 注册进来了 if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames();//从注册器里面获得 BeanDefinitionNames Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));//candidateNames 转换 set Set<String> alreadyParsedClasses = new HashSet<>(); //循环 alreadyParsed。把类名加入到 alreadyParsedClasses 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 && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } }
- 获得所有的 BeanName,放入 candidateNames 数组。
- 循环 candidateNames 数组,根据 beanName 获得 BeanDefinition,判断此 BeanDefinition 是否已经被处理过了。
- 判断是否是配置类,如果是的话。加入到 configCandidates 数组,在判断的时候,还会标记配置类属于 Full 配置类,还是 Lite 配置类,这里会引发一连串的知识盲点:
3.1 当我们注册配置类的时候,可以不加@Configuration 注解,直接使用@Component @ComponentScan @Import @ImportResource 等注解,Spring 把这种配置类称之为 Lite 配置类, 如果加了@Configuration 注解,就称之为 Full 配置类。
3.2 如果我们注册了 Lite 配置类,我们 getBean 这个配置类,会发现它就是原本的那个配置类,如果我们注册了 Full 配置类,我们 getBean 这个配置类,会发现它已经不是原本那个配置类了,而是已经被 cgilb 代理的类了。
3.3 写一个 A 类,其中有一个构造方法,打印出“你好”,再写一个配置类,里面有两个被@bean 注解的方法,其中一个方法 new 了 A 类,并且返回 A 的对象,把此方法称之为 getA,第二个方法又调用了 getA 方法,如果配置类是 Lite 配置类,会发现打印了两次“你好”,也就是说 A 类被 new 了两次,如果配置类是 Full 配置类,会发现只打印了一次“你好”,也就是说 A 类只被 new 了一次,因为这个类被 cgilb 代理了,方法已经被改写。
3.4 具体的可以看我的这篇博客:https://www.cnblogs.com/CodeBear/p/10304605.html,里面有详细的说明。 - 如果没有配置类直接返回。
- 处理排序。
- 解析配置类,可能是 Full 配置类,也有可能是 Lite 配置类,这个小方法是此方法的核心,稍后具体说明。
- 在第 6 步的时候,只是注册了部分 Bean,像 @Import @Bean 等,是没有被注册的,这里统一对这些进行注册。
下面是解析配置类的过程:
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<>(); //循环传进来的配置类 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition();//获得 BeanDefinition try { //如果获得 BeanDefinition 是 AnnotatedBeanDefinition 的实例 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); } } //执行 DeferredImportSelector processDeferredImportSelectors(); }
因为可以有多个配置类,所以需要循环处理。我们的配置类的 BeanDefinition 是 AnnotatedBeanDefinition 的实例,所以会进入第一个 if:
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); this.knownSuperclasses.values().removeIf(configClass::equals); } } // 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); }
重点在于 doProcessConfigurationClass 方法,需要特别注意,最后一行代码,会把 configClass 放入一个 Map,会在上面第 7 步中用到。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //递归处理内部类,一般不会写内部类 // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass); // Process any @PropertySource annotations //处理@PropertySource 注解,@PropertySource 注解用来加载 properties 文件 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 //获得 ComponentScan 注解具体的内容,ComponentScan 注解除了最常用的 basePackage 之外,还有 includeFilters,excludeFilters 等 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); //如果没有打上 ComponentScan,或者被@Condition 条件跳过,就不再进入这个 if if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { //循环处理 componentScans for (AnnotationAttributes componentScan : componentScans) { // The config class is annotated with @ComponentScan -> perform the scan immediately //componentScan 就是@ComponentScan 上的具体内容,sourceClass.getMetadata().getClassName()就是配置类的名称 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) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { //递归调用,因为可能组件类有被@Bean 标记的方法,或者组件类本身也有 ComponentScan 等注解 parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations //处理@Import 注解 //@Import 注解是 spring 中很重要的一个注解,Springboot 大量应用这个注解 //@Import 三种类,一种是 Import 普通类,一种是 Import ImportSelector,还有一种是 Import ImportBeanDefinitionRegistrar //getImports(sourceClass)是获得 import 的内容,返回的是一个 set processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations //处理@ImportResource 注解 AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { 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); } } //处理@Bean 的方法,可以看到获得了带有@Bean 的方法后,不是马上转换成 BeanDefinition,而是先用一个 set 接收 // 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 != null && !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; }
- 递归处理内部类,一般不会使用内部类。
- 处理@PropertySource 注解,@PropertySource 注解用来加载 properties 文件。
- 获得 ComponentScan 注解具体的内容,ComponentScan 注解除了最常用的 basePackage 之外,还有 includeFilters,excludeFilters 等。
- 判断有没有被@ComponentScans 标记,或者被@Condition 条件带过,如果满足条件的话,进入 if,进行如下操作:
4.1 执行扫描操作,把扫描出来的放入 set,这个方法稍后再详细说明。
4.2 循环 set,判断是否是配置类,是的话,递归调用 parse 方法,因为被扫描出来的类,还是一个配置类,有@ComponentScans 注解,或者其中有被@Bean 标记的方法 等等,所以需要再次被解析。 - 处理@Import 注解,@Import 是 Spring 中很重要的一个注解,正是由于它的存在,让 Spring 非常灵活,不管是 Spring 内部,还是与 Spring 整合的第三方技术,都大量的运用了@Import 注解,@Import 有三种情况,一种是 Import 普通类,一种是 Import ImportSelector,还有一种是 Import ImportBeanDefinitionRegistrar,getImports(sourceClass)是获得 import 的内容,返回的是一个 set,这个方法稍后再详细说明。
- 处理@ImportResource 注解。
- 处理@Bean 的方法,可以看到获得了带有@Bean 的方法后,不是马上转换成 BeanDefinition,而是先用一个 set 接收。
我们先来看 4.1 中的那个方法:
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { //扫描器,还记不记在 new AnnotationConfigApplicationContext 的时候 //会调用 AnnotationConfigApplicationContext 的构造方法 //构造方法里面有一句 this.scanner = new ClassPathBeanDefinitionScanner(this); //当时说这个对象不重要,这里就是证明了。常规用法中,实际上执行扫描的只会是这里的 scanner 对象 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")); //addIncludeFilter addExcludeFilter,最终是往 List<TypeFilter>里面填充数据 //TypeFilter 是一个函数式接口,函数式接口在 java8 的时候大放异彩,只定义了一个虚方法的接口被称为函数式接口 //当调用 scanner.addIncludeFilter scanner.addExcludeFilter 仅仅把 定义的规则塞进去,并么有真正去执行匹配过程 //处理 includeFilters for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) { for (TypeFilter typeFilter : typeFiltersFor(filter)) { scanner.addIncludeFilter(typeFilter); } } //处理 excludeFilters 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[] basePackagesArray = componentScan.getStringArray("basePackages"); for (String pkg : basePackagesArray) { String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); Collections.addAll(basePackages, tokenized); } // 从下面的代码可以看出 ComponentScans 指定扫描目标,除了最常用的 basePackages,还有两种方式 // 1.指定 basePackageClasses,就是指定多个类,只要是与这几个类同级的,或者在这几个类下级的都可以被扫描到,这种方式其实是 spring 比较推荐的 // 因为指定 basePackages 没有 IDE 的检查,容易出错,但是指定一个类,就有 IDE 的检查了,不容易出错,经常会用一个空的类来作为 basePackageClasses // 2.直接不指定,默认会把与配置类同级,或者在配置类下级的作为扫描目标 for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(declaringClass)); } //把规则填充到排除规则:List<TypeFilter>,这里就把 注册类自身当作排除规则,真正执行匹配的时候,会把自身给排除 scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) { @Override protected boolean matchClassName(String className) { return declaringClass.equals(className); } }); //basePackages 是一个 LinkedHashSet<String>,这里就是把 basePackages 转为字符串数组的形式 return scanner.doScan(StringUtils.toStringArray(basePackages)); }
- 定义了一个扫描器 scanner,还记不记在 new AnnotationConfigApplicationContext 的时候,会调用 AnnotationConfigApplicationContext 的构造方法,构造方法里面有一句 this.scanner = new ClassPathBeanDefinitionScanner(this);当时说这个对象不重要,这里就是证明了。常规用法中,实际上执行扫描的只会是这里的 scanner 对象。
- 处理 includeFilters,就是把规则添加到 scanner。
- 处理 excludeFilters,就是把规则添加到 scanner。
- 解析 basePackages,获得需要扫描哪些包。
- 添加一个默认的排除规则:排除自身。
- 执行扫描,稍后详细说明。
这里需要做一个补充说明,添加规则的时候,只是把具体的规则放入规则类的集合中去,规则类是一个函数式接口,只定义了一个虚方法的接口被称为函数式接口,函数式接口在 java8 的时候大放异彩,这里只是把规则方塞进去,并没有真正执行匹配规则。
我们来看看到底是怎么执行扫描的:
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); //循环处理 basePackages for (String basePackage : basePackages) { //根据包名找到符合条件的 BeanDefinition 集合 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); //由 findCandidateComponents 内部可知,这里的 candidate 是 ScannedGenericBeanDefinition //而 ScannedGenericBeanDefinition 是 AbstractBeanDefinition 和 AnnotatedBeanDefinition 的之类 //所以下面的两个 if 都会进入 if (candidate instanceof AbstractBeanDefinition) { //内部会设置默认值 postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { //如果是 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; }
因为 basePackages 可能有多个,所以需要循环处理,最终会进行 Bean 的注册。下面再来看看 findCandidateComponents 方法:
public Set<BeanDefinition> findCandidateComponents(String basePackage) { //spring 支持 component 索引技术,需要引入一个组件,因为大部分情况不会引入这个组件 //所以不会进入到这个 if if (this.componentsIndex != null && indexSupportsIncludeFilters()) { return addCandidateComponentsFromIndex(this.componentsIndex, basePackage); } else { return scanCandidateComponents(basePackage); } }
Spring 支持 component 索引技术,需要引入一个组件,大部分项目没有引入这个组件,所以会进入 scanCandidateComponents 方法:
private Set<BeanDefinition> scanCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { //把 传进来的类似 命名空间形式的字符串转换成类似类文件地址的形式,然后在前面加上 classpath*: //即:com.xx=>classpath*:com/xx/**/*.class String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; //根据 packageSearchPath,获得符合要求的文件 Resource[] resources = getResourcePatternResolver().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 元数据读取器,解析 resource,也可以理解为描述资源的数据结构 MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); //在 isCandidateComponent 方法内部会真正执行匹配规则 //注册配置类自身会被排除,不会进入到这个 if 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; }
- 把传进来的类似命名空间形式的字符串转换成类似类文件地址的形式,然后在前面加上 classpath,即:com.xx=>classpath:com/xx/**/*.class。
- 根据 packageSearchPath,获得符合要求的文件。
- 循环符合要求的文件,进一步进行判断。
最终会把符合要求的文件,转换为 BeanDefinition,并且返回。
直到这里,上面说的 4.1 中提到的方法终于分析完毕了,让我们再看看上面提到的第 5 步中的处理@Import 注解方法:
//这个方法内部相当相当复杂,importCandidates 是 Import 的内容,调用这个方法的时候,已经说过可能有三种情况 //这里再说下,1.Import 普通类,2.Import ImportSelector,3.Import ImportBeanDefinitionRegistrar //循环 importCandidates,判断属于哪种情况 //如果是普通类,会进到 else,调用 processConfigurationClass 方法 //这个方法是不是很熟悉,没错,processImports 这个方法就是在 processConfigurationClass 方法中被调用的 //processImports 又主动调用 processConfigurationClass 方法,是一个递归调用,因为 Import 的普通类,也有可能被加了 Import 注解,@ComponentScan 注解 或者其他注解,所以普通类需要再次被解析 //如果 Import ImportSelector 就跑到了第一个 if 中去,首先执行 Aware 接口方法,所以我们在实现 ImportSelector 的同时,还可以实现 Aware 接口 //然后判断是不是 DeferredImportSelector,DeferredImportSelector 扩展了 ImportSelector //如果不是的话,调用 selectImports 方法,获得全限定类名数组,在转换成类的数组,然后再调用 processImports,又特么的是一个递归调用... //可能又有三种情况,一种情况是 selectImports 的类是一个普通类,第二种情况是 selectImports 的类是一个 ImportBeanDefinitionRegistrar 类,第三种情况是还是一个 ImportSelector 类... //所以又需要递归调用 //如果 Import ImportBeanDefinitionRegistrar 就跑到了第二个 if,还是会执行 Aware 接口方法,这里终于没有递归了,会把数据放到 ConfigurationClass 中的 Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars 中去 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) { if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
这个方法大概的作用已经在注释中已经写明了,就不再重复了。
直到这里,才把 ConfigurationClassPostProcessor 中的 processConfigBeanDefinitions 方法简单的过了一下。
但是这还没有结束,processConfigBeanDefinitions 是 BeanDefinitionRegistryPostProcessor 接口中的方法,BeanDefinitionRegistryPostProcessor 扩展了 BeanFactoryPostProcessor,还有 postProcessBeanFactory 方法没有分析,这个方法是干嘛的,简单的来说,就是判断配置类是 Lite 配置类,还是 Full 配置类,如果是配置类,就会被 Cglib 代理,目的就是保证 Bean 的作用域。关于这个方法实在是比较复杂,限于篇幅原因,这里就不再继续了,有兴趣的朋友可以到我的 GitHub 看下,里面有简单的分析(当然其实还有很多东西无法在博客中体现,如果都贴出来的话,实在是太长了,但是在 GitHub 上面都有注释)。
我们来做一个总结,ConfigurationClassPostProcessor 中的 processConfigBeanDefinitions 方法十分重要,主要是完成扫描,最终注册我们定义的 Bean。
【注:本文源自网络文章资源,由站长整理发布】