spring源码分析(1)——AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

为了更容易的理解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接下来的初始化中发挥作用。


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring源码分析(1)——AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏