聊聊Spring框架的源码,本博客讲解的Spring源码版本是5.3.10。博客会分为上中下三篇,上篇聊Spring的Bean扫描,中篇聊Bean的实例化,下篇聊Bean的初始化(属性注入与AOP)。
以普通的Java项目为例,我是以AnnotationConfigApplicationContext类作为切入点开始研究的,先看看它的父类/接口:
发现该类实现了很多接口:
- ApplicationEventPublisher:实现该接口,具备事件发布的能力;
- AnnotationConfigRegistry:实现该接口,具备基于注解的配置类的注册功能;
- ApplicationContext:实现该接口,具备获取某些应用上下文信息的能力;
- BeanDefinitionRegistry:实现该接口,具备注册/移除 Bean对象的能力;
- ResourceLoader:实现该接口,具备加载资源的功能,可以方便地加载类路径下的文件、图片等资源;
- BeanFactory:实现该接口,具备"获取" Bean对象的能力;
- MessageSource:实现该接口,提供了国际化支持,可以方便地加载不同语言环境下的消息资源;
- ResourcePatternResolver:实现该接口,具备解析资源的能力,比如解析 classpath:/beans.xml;
- EnvironmentCapable:实现该接口,具备获取环境信息,比如系统属性、环境变量、配置文件中的属性等;
- HierarchicalBeanFactory:实现该接口,具备获取 ParentBeanFactory的能力;
- ListableBeanFactory:实现该接口,可获取"多个" Bean、BeanName、BeanDefinitionNames等;
- AbstractApplicationContext:继承了该抽象类,有一些公共的功能都是在此类中的方法中实现,包括最为重要的 refresh()方法。
由此可知,由于AnnotationConfigApplicationContext继承了AbstractApplicationContext并且实现了很多接口,因此它有很多功能,这块在后面遇到了再讲。以上只是对AnnotationConfigApplicationContext的大致了解,先了解其功能,再带着问题去看,效率会高一些。
回到开头说的,从入口开始切入,首先是创建AnnotationConfigApplicationContext对象,有有参构造和无参构造,这里我使用的是有参构造,可以传入一个配置类,配置类一般是被@ComponentScan:指定包路径,用于包扫描、@PropertySource:指定配置文件的路径,用于解析配置后缀是 properties的文件。如下图所示:
可以看到,在该构造中,会先调用无参的构造方法,再看看无参构造方法,在该方法中,初始化了两个对象,即AnnotatedBeanDefinitionReader,赋值给 reader,ClassPathBeanDefinitionScanner赋值给 scanner,由类名可知,AnnotatedBeanDefinitionReader用于将注解类解析成BeanDefinition,ClassPathBeanDefinitionScanner则用于扫描classpath目录下的类,将其解析为BeanDefinition。实际上ClassPathBeanDefinitionScanner虽然被构建了,但是后续并没有使用,除非调用AnnotationConfigApplicationContext#scan(String... basePackages)方法,才会被调用,如下图所示:
继续往下看,由于AnnotationConfigApplicationContext继承了GenericApplicationContext、GenericApplicationContext继承了AbstractApplicationContext,由于在 Java中创建某个对象 ,如果该类继承了其他类,优先调用父类的构造,因此需要看一下AnnotationConfigApplicationContext父类、以及它父类的父类的构造,如下图所示:
可知在GenericApplicationContext类中有一个成员属性,即beanFactory,在它的无参构造中,创建了DefaultListableBeanFactory对象,并赋值给 beanFactory,beanFactory才是Spring真正的IOC容器,也就是说调用 AnnotationConfigApplicationContext#getBean(String beanName),实际上是从beanFactory获取 bean对象。再看看DefaultListableBeanFactory的无参构造,如下图所示:
主要是设置了三个忽略的接口,即:BeanNameAware、BeanFactoryAware、BeanClassLoaderAware。并且创建了CglibSubclassingInstantiationStrategy对象(这里可以打断点看是进的if还是else)。至于设置的忽略列表,后续会讲到,这里留一个悬念。
回到AnnotationConfigApplicationContext的无参构造,实际上在初始化AnnotatedBeanDefinitionReader对象的时候,在它的构造中也做了一些初始化的工作,如下图所示:
看代码可知:调用了AnnotatedBeanDefinitionReader#getOrCreateEnvironment(BeanDefinitionRegistry registry)方法,创建/获取Environment对象,作为ConditionEvaluator的构造方法的入参,创建了ConditionEvaluator对象,并赋值给 conditionEvaluator,用于解析条件注解 @Conditional;
到这里就很清晰了,AnnotationConfigApplicationContext的父类,即AbstractApplicationContext的environment成员属性,就是在这里创建并初始化的。再次回到AnnotationConfigUtils#registerAnnotationConfigProcessors()方法中(代码截图在上面),调用AnnotationConfigUtils#unwrapDefaultListableBeanFactory(BeanDefinitionRegistry registry)方法,获取DefaultListableBeanFactory对象,也就是获取GenericApplicationContext的成员属性beanFactory,并给beanFactory设置属性:
- 创建AnnotationAwareOrderComparator对象,设置给 dependencyComparator,针对 @Order、@Priority、Ordered接口,用于排序,以@Order接口为例,int value()值越小越靠前;
- 创建 ContextAnnotationAutowireCandidateResolver对象,并将其赋值给autowireCandidateResolver,用于判断某些 Bean对象能否被依赖注入,以及针对被 @Lazy注解修饰的属性(类),会创建一个代理对象并进行赋值等;
然后判断AnnotationConfigApplicationContext#containsBeanDefinition(String beanName)方法,判断某些类是否已经被加载过了,如果没有,则加载。
- ConfigurationClassPostProcessor是否被加载,该类实现了BeanDefinitionRegistryPostProcessor,用于解析配置类,是 BeanFactory的后置处理器,调用的优先级,高于 Bean的后置处理器;
- AutowiredAnnotationBeanPostProcessor是否被加载,该类实现了SmartInstantiationAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor等接口,是 Bean后置处理器,用于处理 @Autowired注解;
- CommonAnnotationBeanPostProcessor是否被加载,该类实现了InstantiationAwareBeanPostProcessor、BeanFactoryAware等接口,是 Bean后置处理器,用于处理一个公共注解,如 @Resource、@PostConstruct、PreDestroy等注解;
- PersistenceAnnotationBeanPostProcessor是否被加载,该类实现了InstantiationAwareBeanPostProcessor、DestructionAwareBeanPostProcessor、MergedBeanDefinitionPostProcessor等接口,用于处理@PersistenceContext、@PersistenceUnit等注解,SpringJPA相关;
- DefaultEventListenerFactory是否被加载,该类实现了EventListenerFactory等接口,唯一的作用就是通过调用DefaultEventListenerFactory#createApplicationListener(String beanName, Class<?> type, Method method)方法,返回ApplicationListenerMethodAdapter对象;
- EventListenerMethodProcessor是否被加载,该类实现了SmartInitializingSingleton、ApplicationContextAware、BeanFactoryPostProcessor等接口,作用就是处理@EventListener注解,该类需配合 DefaultEventListenerFactory,也就是说,如果一个A类中有一个方法b,是被@EventListener注解所修饰,则Spring会调用DefaultEventListenerFactory#createApplicationListener()方法,创建一个ApplicationListenerMethodAdapter对象并放入AbstractApplicationContext的 Set<ApplicationListener<?>> applicationListeners属性中,该对象实际上是实现了GenericApplicationListener接口,它会实现GenericApplicationListener#onApplicationEvent()方法,最终发布与之匹配事件的时候,通过反射,调用 A#b()方法。
调用 ApplicationListenerMethodAdapter#onApplicationEvent(ApplicationEvent event)方法:
以上,就是AnnotationConfigUtils#registerAnnotationConfigProcessors()方法的所有逻辑,回到AnnotationConfigApplicationContext的无参构造,看看scanner属性被初始化,也就是创建 ClassPathBeanDefinitionScanner对象,看看它的有参构造,如下图所示:
由于入参 useDefaultFilters,传入的值为 true,因此进入if代码块:
会创建AnnotationTypeFilter,传入 Component.class,即@Component注解,如果javax.annotation.ManagedBean存在(依赖是否存在),或者javax.inject.Named存在(依赖是否存在),也会创建相应的AnnotationTypeFilter对象,并放入List<TypeFilter> includeFilters中。也就是说,如果类上被@Component、@ManagedBean、@Named注解修饰,则该类会被加载到Spring容器中(这么说不严谨,其实还有其他的限制条件,后面会提到)。
回到AnnotationConfigApplicationContext得有参构造,如下图所示:
看看AnnotationConfigApplicationContext#register(Class<?>... componentClasses)方法,实际上就是将传入的class对象注册到spring容器中,也就是AppConfig.class,最终将AppConfig.class转换为BeanDefinition对象,并且还要解析AppConfig上的注解,诸如:@Primary、@Lazy、@DependsOn、@Role、@Description等,最后将该BeanDefinition放入 DefaultListableBeanFactory的 beanDefinitionMap属性中,beanName放入 beanDefinitionNames中,完成Bean的注册。
再回到AnnotationConfigApplicationContext的有参构造中,调用了最为核心的AnnotationConfigApplicationContext#refresh()方法,实际上是调用了父类的该方法,这里使用了模板方法设计模式,会调用很多其他方法,有些在AbstractApplicationContext中实现了,而有些则是在其子类中实现。具体如下图所示:
1.AbstractApplicationContext#prepareRefresh()方法,做一些前置准备,如一些属性设置,比如设置 closed为false,active为true,给earlyApplicationListeners、earlyApplicationEvents等属性赋值,调用AbstractApplicationContext#initPropertySources()方法,如果是web应用,则该方法将会起作用,如下图所示:
由上面的代码可知,如果ServletContext对象不为空,则会创建ServletContextPropertySource对象,保存ServletContext;ServletConfig对象不为null,则会创建ServletConfigPropertySource对象,保存ServletConfig对象,并将ServletContextPropertySource对象、ServletConfigPropertySource对象保存到 StandardServletEnvironment对象中的propertySources属性中,后续就可以直接中环境变量Environment对象中拿到你想到的属性值。
2.AbstractApplicationContext#obtainFreshBeanFactory()方法,如下图所示:
判断Spring容器是否已经刷新过,如果是,则抛异常。
可以知道,实际上obtainFreshBeanFactory()方法就是得到 beanFactory属性,用于后续处理。
3.AbstractApplicationContext#prepareBeanFactory()方法,如下图所示:
做了这么几件事:
①给beanFactory对象设置ClassLoader,优先从当前线程中获取ClassLoader,如果是跟其他框架整合,如Tomcat,则Tomcat可以将自定义的ClassLoader设置到当前线程中,进而被Spring容器获取到并设置,后续使用的ClassLoader都是使用Tomcat自定义的类加载器;
②beanFactory对象是否启用Spel功能,如果启用,则设置StandardBeanExpressionResolver对象,用于处理Spel表达式;
③给beanFactory对象添加一个类型转换器,即ResourceEditorRegistrar对象;
④给beanFactory对象添加一个后置处理器,即ApplicationContextAwareProcessor对象,用于处理实现了某些接口的方法回调,如下图所示:
⑤设置忽略的接口列表(之前设置过一次):EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、ApplicationStartupAware;
⑥设置如果依赖了某些接口,则应该注入什么样的对象(因为这些接口在Spring的IOC容器中并没有相应的对象,如果不这么做,则会找不到要注入的对象,进而报错)。如:依赖了BeanFactory,实际上注入的就是 beanFactory(AbstractApplicationContext的属性)、依赖了ResourceLoader、ApplicationEventPublisher或者ApplicationContext,最终注入的都是AnnotationConfigApplicationContext对象;
⑦给beanFactory对象添加一个后置处理器,即ApplicationListenerDetector对象,如下图所示:
⑧手动往beanFactory中注册一些单例Bean,如
beanName为 “environment”,bean为 ConfigurableEnvironment 对象、
beanName为 “systemProperties”,bean为 Map<String, Object> 对象、
beanName为 “systemEnvironment”,bean为 Map<String, Object> 对象、
beanName为 “applicationStartup”,bean为 ApplicationStartup 对象;
4.AbstractApplicationContext#postProcessBeanFactory()方法,如下图所示:
空实现,由此可知是为了让子类来实现的。
5.AbstractApplicationContext#invokeBeanFactoryPostProcessors()方法,如下图所示:
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法,代码很多,逻辑较复杂,这里就不全贴出来了,感兴趣的小伙伴可以自己去看看,我大概说下里面干了些啥:主要是调用实现了BeanFactoryPostProcessor接口、BeanDefinitionRegistryPostProcessor(他的父接口为 BeanFactoryPostProcessor)接口的类。当然,是按照一定的顺序:
①程序员调用ApplicationContext的API手动添加;
②Spring自己扫描出来的;
具体的执行顺序如下:
1) 执行手动添加的BeanDefinitionRegistryPostProcessor 的postProcessBeanDefinitionRegistry()方法;
2) 执行扫描出来的BeanDefinitionRegistryPostProcessor(实现了PriorityOrdered)的postProcessBeanDefinitionRegistry()方法;
3) 执行扫描出来的BeanDefinitionRegistryPostProcessor(实现了Ordered) 的postProcessBeanDefinitionRegistry()方法;
4) 执行扫描出来的BeanDefinitionRegistryPostProcessor(普通) 的postProcessBeanDefinitionRegistry()方法;
5) 执行扫描出来的BeanDefinitionRegistryPostProcessor(所有) 的postProcessBeanFactory()方法;
6) 执行手动添加的BeanFactoryPostProcessor 的postProcessBeanFactory()方法;
7) 执行扫描出来的BeanFactoryPostProcessor(实现了PriorityOrdered) 的postProcessBeanFactory()方法;
8) 执行扫描出来的BeanFactoryPostProcessor(实现了Ordered) 的postProcessBeanFactory()方法;
9) 执行扫描出来的BeanFactoryPostProcessor(普通) 的postProcessBeanFactory()方法。
在这里我并没有手动添加任何BeanFactoryPostProcessor对象,因此没有可执行的,针对Spring扫描的,此时还没有到包扫描那一步,因此也没有。但是还有唯一一个实现的BeanDefinitionRegistryPostProcessor接口的实现类,那就是之前在初始化AnnotatedBeanDefinitionReader的时候,唯一添加的一个,代码如下图所示:
因此,将会执行ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法,如下图所示:
该类就是专门处理配置类,何为配置类?下面就会详细说明。继续看ConfigurationClassPostProcessor#processConfigBeanDefinitions()方法,方法较长,只截取核心代码,如下图所示:
以上截取的代码,我在这里做一下总结。也就是说:首先会获取到所有的beanName,然后遍历,通过beanName,得到BeanDefinition对象,然后判断BeanDefinition是否是配置类?只有BeanDefinition对应的类,被@Configuration注解修饰,并且proxyBeanMethods属性为true,则是Full配置类,给该BeanDefinition对象设置属性configurationClass为"full";如果该类是被@Configuration注解修饰,但是proxyBeanMethods属性为false,或者是被@Component、@ComponentScan、@Import、@ImportResource中的一个注解所修饰,或者类中有方法是被@Bean注解修饰,则都可视为这个类是配置类,只不过它是lite配置类,并且给该BeanDefinition对象设置属性configurationClass为"lite"。
遍历完成,可以得到一些配置类,就包括我定义的类,即 AppConfig。接着就是处理这些配置类了,通过do/while处理配置类,为什么通过do/while循环呢?因为找出了第一批配置类后,后续可能在扫描的时候,找到其他的类,可能也是配置类,因此后续还需要继续扫描,所以使用do/while来处理。如下图所示:
由于这里主要添加了注解的类讲解,因此进入到上图 if代码块中。
关于条件注解这里,可以聊聊。这里,先判断类上是否加了@Conditional注解,如果没加,返回false,不做处理。如果加了@Conditional注解,,则调用@Conditional的 value()方法,得到Class的数组,并通过反射将其实例化,并且这些类一定是实现了Condition接口的,然后遍历调用 Condition#matches()方法,如果结果返回 false,则表示该类不满足条件注解的要求,则跳过不处理。
调用ConfigurationClassParser#doProcessConfigurationClass()方法,如下图所示:
该方法是处理配置类的核心方法,主要做了这么几件事:
①如果该类是被@Component注解修饰,则判断其是否有内部类,如果有,则判断其内部类是否是配置类,如果是,则加入candidates(List)中,然后遍历,调用ConfigurationClassParser#processConfigurationClass()方法,传入内部类,当作配置类处理,如下图所示:
②判断类上是否被@PropertySources、@PropertySource注解修饰,如果是,则得到文件地址,并进行解析,将解析到的配置放入Environment中,如下图所示:
③判断类上是否被@ComponentScans、@ComponentScan注解修饰,则调用ComponentScanAnnotationParser#parse()方法,进行解析,如下图所示:
由上面的代码可知:通过解析@ComponentScan注解,得到包路径,以AppConfig为例,扫描得到的包名为:com.szl,经过字符拼接等处理,得到:classpath*:com/szl/**/*.class 。找到所有的class的路径,并解析得到Resource的数组,遍历,调用ClassPathScanningCandidateComponentProvider#isCandidateComponent(MetadataReader metadataReader)方法,只有该类不满足 excludeFilters并且满足 includeFilters,则才是候选class,再调用ClassPathScanningCandidateComponentProvider#isCandidateComponent(AnnotatedBeanDefinition sdb)方法,在该方法中会再次判断:
1) 只有该类是独立的(不是内部类,或者是静态内部类);
2) 该类不是接口或者抽象类;
3) 是抽象类,但是类中有方法被@Lookup注解修饰。
满足上述上个条件中的一个,该类才会被放入candidates中。
回到ClassPathBeanDefinitionScanner@doScan()方法,遍历candidates,解析类上是否被某些注解修饰(@Lazy、@Primary、@DependsOn、@Role、@Description),有则处理之。然后调用ClassPathBeanDefinitionScanner@checkCandidate()方法,检查是否有重名的类,如果有,判断其是否兼容,如果兼容返回false,表示不会重新注册到Spring容器中,否则抛异常。如果校验通过,则将其注册到Spring容器中。
④ 调用ConfigurationClassParser#processImports()方法,处理@Import注解,如下图所示:
该方法,主要是解析@Import注解,获取注解里面的Class,针对Class,实际上有三种情况:
1) 实现了ImportSelector接口,则会通过反射创建该对象,调用ImportSelector#selectImports()方法,返回的是String数组,也就是多个类的全限定名的字符串集合,并将其解析为 SourceClass的集合,继续调用 processImports()方法,进行递归处理;如果是实现了DeferredImportSelector接口(即 ImportSelector的子类),会先缓存起来,等待这轮配置类解析结束了再处理它。该类在SpringBoot中使用很多,由于其相较于配置类延迟加载的特点,可以实现用户配置大于默认,比如说StringBoot的Web项目,默认使用的是Tomcat作为web容器,如果用户依赖的Jetty,则SpringBoot在启动的过程中,会优先解析Jetty相关配置,由于它自己的Tomcat配置是在通过 DeferredImportSelector做的,因此Tomcat相关配置的解析就是在用户设置之后,再配合条件注解,判断此时是否存在了 Jetty相关的Class,如果存在,则使用用户手动设置的Jetty,而不是默认的Tomcat;
2) 实现了ImportBeanDefinitionRegistrar接口,会通过反射创建对象,并设置到的ConfigurationClass(即当前正在解析的配置类)的importBeanDefinitionRegistrars属性中,缓存起来,后续处理;
3) 普通的类,针对这种,Spring会直接将其当作配置类解析,即调用ConfigurationClassParser#processConfigurationClass()方法。
⑤ 处理@ImportResource注解,拿到注解中配置的locations和reader,也不会马上处理,而是设置到ConfigurationClass的importedResources属性中;
⑥ 调用ConfigurationClassParser#retrieveBeanMethodMetadata()方法,解析配置类中,是否有被@Bean注解修饰的方法,如果有,则创建BeanMethod对象,放入ConfigurationClass的beanMethods属性中 ,后面处理;
⑦ 递归调用ConfigurationClassParser#processInterfaces()方法,解析配置类是否实现了接口(类可以实现多个接口,并且接口可以继承接口,所以要递归处理),如果实现了,判断接口中是否有被@Bean注解修饰的方法,如果有,则创建BeanMethod对象,放入ConfigurationClass的beanMethods属性中 ,后面处理;
⑧ 判断配置类是否有父类,如果有,返回父类,如果没有返回null,在调用doProcessConfigurationClass()方法的地方会判断返回的对象是否为空,不会空则会继续解析父类;
⑨ 最后将配置类放入ConfigurationClassParser对象的configurationClasses属性中,因为配置类除了需要解析外,最终也是要放入Spring的IOC容器的。
回到调用parser.parse(candidates)的地方继续往下看,由于前面解析配置类的时候,有些情况没有处理,现在需处理,代码如下:
因此,调用 this.reader.loadBeanDefinitions(configClasses)方法,处理,进入该方法:
做了这么几件事:
1) @Component的内部类,@Import所导入的类都是被导入的类,都会放入Spring的IOC容器中;
2) @Bean注解修饰的方法,会被解析生成BeanDefinition并注册到Spring容器中;
3) 处理@ImportResource("spring.xml");
4) 处理通过@Import导入,并且实现了ImportBeanDefinitionRegistrar接口的Class,调用registerBeanDefinitions()方法。
到这里,配置类的处理逻辑基本上是处理得差不多了,由于这块的逻辑是在do/while中 ,会比较判断除去之前的配置类,是否还有多余的配置类,有就放入candidates中,如果candidates不为空,则继续处理新增的配置类。
到这里为止,ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法,基本上处理完了。此时,Spring容器中会出现很多新的BeanDefinition对象,这些对象,都存在DefaultListableBeanFactory的beanDefinitionMap属性中,这些BeanDefinition对象的来源包括:包扫描、@Import导入、@Bean等等。
回到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法,除了调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法外,还会调用ConfigurationClassPostProcessor#postProcessBeanFactory()方法,代码如下:
看到这里,大概就清楚了:对于配置类的configurationClass属性是"full"的,则会通过GCLib生成代理的Class,并将该Class设置到该配置类对应的BeanDefinition的beanClass属性中,后续生成Bean对象,就是基于这个beanClass属性,通过反射生成的。对于通过CGLib生成的代理对象,要看它的处理逻辑,只需要看设置的Callback对象即可,也就是BeanMethodInterceptor,准确的说是BeanMethodInterceptor#intercept()方法。
在该方法中,会处理该配置类中添加了@Bean注解的方法。因为会有这么一种情况:如果在一个配置类中有两个方法是被@Bean修饰的,其中一个方法的返回对象,是另一个方法的入参,针对这种情况,有两种处理,一种是直接通过入参的形式(@Autowired可加可不加);还有一种是直接在方法中调用另一个方法,得到依赖的对象。如果是第一种情况,没啥问题;如果是针对第二种情况,就有问题了,假如说那个被依赖的对象对应的方法已经被Spring调用过了,此时Spring容器中已经存在了这个Bean,如果另一个方法通过直接方法调用的是形式,得到新的对象,那此时这个被依赖的对象不就有两个了吗?针对Bean,如果没有显式声明的话,默认都是单例的,这不符合Spring的设计思想,因此,第二种情况必须处理,这也是BeanMethodInterceptor#intercept()方法干的事,如果是直接方法调用,会先进到intercept()方法中,先判断该被依赖的对象那个是否已经在Spring的IOC容器存在,如果存在了,直接获取到这个对象返回,如果没有,则调用这个方法,创建对象,在返回的该对象同时,也把这个创建的对象那个放到Spring的IOC容器中,后续就不会再创建该对象了。
6.到这里为止,AbstractApplicationContext#invokeBeanFactoryPostProcessors()方法已全部讲解完,然后就是AbstractApplicationContext#registerBeanPostProcessors()方法,代码如下:
看代码可以知道:这里主要是将各种BeanPostProcessor进行实例化,因为后续生成Bean对象的时候会调用后置处理器的某些方法,因此需要提前实例化。并且由于BeanPostProcessor还有各种子类,因此针对不同的后置处理器会进行分类,放入不同的List中供后续使用(后续就不用过滤了)。当然,针对实现了PriorityOrdered、Ordered接口的,会进行排序,没有实现这些排序接口的后置处理器,默认值排序值为0(值越小越靠前)。
7.AbstractApplicationContext#initMessageSource()方法,这一块是国际化相关,代码如下:
通过beanName判断,即"messageSource",到Spring容器中查询是否存在,如果存在,则获取MessageSource对象,如果parentMessageSource属性为空,则拿父ApplicationContext的messageSource给parentMessageSource属性赋值;如果不存在,则创建DelegatingMessageSource对象,则拿父ApplicationContext的messageSource给parentMessageSource属性赋值,最后将DelegatingMessageSource对象直接放入单例池中,beanName当然就是"messageSource"了。
8.AbstractApplicationContext#initApplicationEventMulticaster()方法,这一块是事件发布相关,代码如下:
同 initMessageSource()方法一样,也会现根据beanName,即"applicationEventMulticaster"判断ApplicationEventMulticaster对象是否存在。如果存在,则获取该对象,并将其赋值给applicationEventMulticaster属性;如果不存在的话,就创建SimpleApplicationEventMulticaster对象,并将其直接放入到单例池中(注意,这里并非创建 BeanDefinition)。
9.AbstractApplicationContext#onRefresh()方法,该方法主要是给子类实现的,该类中的方法为空实现。
10.AbstractApplicationContext#registerListeners()方法,该方法就是将Spring容器中所有的ApplicationListener对象注册到ApplicationEventMulticaster对象中,代码如下:
由代码可知,当发布了一个事件,最终一定是调用到了SimpleApplicationEventMulticaster对象中的某个方法,看看该类中的方法,除了添加/移除ApplicationListener之类的方法,还有一个SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent event)方法,这里就是真正处理事件的方法,代码如下:
以上,就是Spring源码解析的部分分容,看到这个,您如果有时间,烦您移步到这一篇文章:Spring源码深度解析(中)。如果文中讲解有误,欢迎批评指正,谢谢!