剑指Spring源码(二)
这是春节后的第一篇博客,我在构思这篇博客的时候,一度想放弃,想想要不要换个东西写,由于毕竟个人水平有限,Spring源码实在博大精深,不是我这个菜的抠脚的菜鸡可以驾驭的,怕误人子弟,还有就是源码分析类的博客实在是太难写了,和一般的博客真心不同,可能写了很多,自己都不知道自己在写些什么,但是还是要坚持,从接触博客的那一天开始,就非常佩服那些大神,乐于分享,无私奉献,我也从那些博客中学到了不少东西,慢慢的从一个嫩嫩的小菜鸡变成了秃头大菜鸡,其中最佩服的就是那些源码分析类的博客,尽管看不懂,但是从博客中,我分明读出了大神们对技术的酷爱,对技术的坚持,对技术的执著。坚持!
在上一篇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.songma.com/p/d001f96933cf,里面有详细的说明。 - 假如没有配置类直接返回。
- 解决排序。
- 解析配置类,可能是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。
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 剑指Spring源码(二)