为了更容易的理解spring源码,我们使用一个简单的hello world的例子来分析。
Spring的版本是5.0.4,需要jdk8以上支持
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.4.RELEASE</version>
</dependency>
</dependencies>
例子来自于Spring官网示例,请自行下载。
首先从main函数开始
publicstatic void main(String[] args) {
ApplicationContext context =
newAnnotationConfigApplicationContext(Application.class);
MessagePrinter printer =context.getBean(MessagePrinter.class);
printer.printMessage();
}
AnnotationConfigApplicationContext 是spring 3.0以后引入的类,用于处理spring注解。
AnnotationConfigApplicationContext继承了GenericApplicationContext,而GenericApplicationContext实现了BeanDefinitionRegistry。
Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。而BeanDefinitionRegistry接口提供了向容器注册,删除,获取BeanDefinition对象的方法。简单来说,BeanDefinitionRegistry可以用来管理BeanDefinition,所以理解AnnotationConfigApplicationContext很关键,它是spring加载bean,管理bean的最重要的类。
我们跟进这个构造方法继续。
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
this()调用本身无参的构造函数。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
AnnotatedBeanDefinitionReader是一个读取注解的Bean读取器,这里将this传了进去。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
这里将AnnotationConfigApplicationContext注册为管理BeanDefinition的BeanDefinitionRegistry,也就是说,spring中bean的管理完全交给了AnnotationConfigApplicationContext。
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中,具体的代码就不粘了,这里加入了如下6个处理器:
1:bean名称为org.springframework.context.annotation.internalConfigurationAnnotationProcessor的ConfigurationClassPostProcessor。
ConfigurationClassPostProcessor是一个BeanFactory和BeanDefinitionRegistry处理器,BeanDefinitionRegistry处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。
ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。
2:bean名称为org.springframework.context.annotation.internalAutowiredAnnotationProcessor的AutowiredAnnotationBeanPostProcessor。AutowiredAnnotationBeanPostProcessor是一个BeanPostProcessor,注意BeanPostProcessor和BeanFactoryPostProcessor的区别。AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的。
3:bean名称为org.springframework.context.annotation.internalRequiredAnnotationProcessor的RequiredAnnotationBeanPostProcessor。这是用来处理@Required注解。
4:bean名称为org.springframework.context.annotation.internalCommonAnnotationProcessor的CommonAnnotationBeanPostProcessor。CommonAnnotationBeanPostProcessor提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
5:bean名称为org.springframework.context.annotation.internalPersistenceAnnotationProcessor的PersistenceAnnotationBeanPostProcessor。EventListenerMethodProcessor提供@PersistenceContext的支持。
6:bean名称为org.springframework.context.annotation.internalEventListenerProcessor的EventListenerMethodProcessor。EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
到此AnnotatedBeanDefinitionReader初始化完毕。总结一下,AnnotatedBeanDefinitionReade读取器用来加载class类型的配置,在它初始化的时候,会预先注册一些BeanPostProcessor和BeanFactoryPostProcessor,这些处理器会在接下来的spring初始化流程中被调用。
接下来初始化ClassPathBeanDefinitionScanner。
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
分析registerDefaultFilters()方法:
ClassPathBeanDefinitionScanner继承了 ClassPathScanningCandidateComponentProvider。registerDefaultFilters() 就是 ClassPathScanningCandidateComponentProvider中的方法。
private final List<TypeFilter> includeFilters = new LinkedList<>();
private final List<TypeFilter> excludeFilters = new LinkedList<>();
....
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
ClassPathScanningCandidateComponentProvider中有两个final类型的List,分别是includeFilters和excludeFilters。这两个对象在ClassPathScanningCandidateComponentProvider这个类执行scanCandidateComponents()方法,也就是扫描给定类路径的包的时候,会充当过滤规则,includeFilters中的就是满足过滤规则的,excludeFilters则是不满足过滤规则的。
该方法为includeFilters加入了三个TypeFilter,具体来说,是三个AnnotationTypeFilter,它是TypeFilter的一个实现,用于判断类的注解修饰型是否满足要求。从中可知通过 @Component、@javax.annotation.ManagedBean 和 @javax.inject.Named 以及标记了这些 Annotation 的新 Annotation 注解过的 Java 对象即为 Spring 框架通过 Annotation 配置的默认规则。注意@service,@controller等都继承了@component,是符合规则的。
分析setResourceLoader ()方法:
@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}
setResourceLoader()方法中为ResourcePatternResolver,MetadataReaderFactory和CandidateComponentsIndex设定初始值。
1:ResourcePatternResolver是一个接口,继承了ResourceLoader,可以用来获取Resource 实例。ResourcePatternResolver中申明它默认的扫描文件 Pattern 为”**/*.class”,我们使用的AnnotationConfigApplicationContext或者说是任何的ApplicationContext都实现了这个接口,所以这里将AnnotationConfigApplicationContext传给了ResourcePatternResolver。
2:MetadataReaderFactory用于解析资源信息对应的元数据。
3:CandidateComponentsIndexLoader.loadIndex () 方法是spring5.0以后加入的新特性,Spring Framework 5 改进了扫描和识别组件的方法,使大型项目的性能得到提升。目前,扫描是在编译时执行的,而且向 META-INF/spring.components 文件中的索引文件添加了组件坐标。该索引是通过一个为项目定义的特定平台应用的构建任务来生成的。标有来自 javax 包的注解的组件会添加到索引中,任何带 @Index 注解的类或接口都会添加到索引中。如果没有META-INF/spring.components这个文件,则返回空,这里返回空。
至此,ClassPathBeanDefinitionScanner初始化完毕,总结一下,ClassPathBeanDefinitionScanner是一个扫描指定类路径中注解Bean定义的扫描器,在它初始化的时候,会初始化一些需要被扫描的注解,初始化用于加载包下的资源的Loader。
AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化是spring上线文初始化的起点,很多预加载的类会在spring接下来的初始化中发挥作用。