前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot源码学习(三)

SpringBoot源码学习(三)

作者头像
写一点笔记
发布2020-09-10 15:45:23
3600
发布2020-09-10 15:45:23
举报
文章被收录于专栏:程序员备忘录程序员备忘录

我们说在springApplication类中中的prepareContext方法中将我们的启动类注册到了spring容器中。当时分析的在loader.load()方法中.那么这个方法又是怎么做的。根据正常的想法我们知道如果拿到了启动类那么就拿到了启动类上边的注解,而启动类上边的注解就包含了太多的信息。通过这些信息就可以将项目所需要的类全部注册到BeanDefinitionLoader中,但是前提是我们要多这个类有所了解。才能逐步去跟进我们的猜想。

打开源码之后,发现这个类提供的方法不多,但是相关的类比较多。

那么咋看看这些类大概都是做什么的

代码语言:javascript
复制
    private final Object[] sources;
    //解析注解的bean
    private final AnnotatedBeanDefinitionReader annotatedReader;
    //注册xml中的bean
    private final XmlBeanDefinitionReader xmlReader;
    private BeanDefinitionReader groovyReader;
    //传入的是包路径
    private final ClassPathBeanDefinitionScanner scanner;
    private ResourceLoader resourceLoader;

大概得想法就是这样,那么程序中是怎么做的?我们详细看一些其提供的各种load方法、

代码语言:javascript
复制
    //根据类型判断采用那种方式进行load
    private int load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class) {
        //传入的是类
            return this.load((Class)source);
        } else if (source instanceof Resource) {
            return this.load((Resource)source);
        } else if (source instanceof Package) {
            return this.load((Package)source);
        } else if (source instanceof CharSequence) {
            return this.load((CharSequence)source);
        } else {
            throw new IllegalArgumentException("Invalid source type " + source.getClass());
        }
    }
代码语言:javascript
复制
    //如果传入的是类,那么就用 annotatedReader注册 
    private int load(Class<?> source) {
        if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
            this.load(loader);
        }

        if (this.isComponent(source)) {
            this.annotatedReader.register(new Class[]{source});
            return 1;
        } else {
            return 0;
        }
    }

其他方法类似。这里不在赘述。我们继续跟踪我们的load方法。

通过查看annotationConfigServletWebServerApplicationContext类的继承关系图,我们发现其本质上有BeanDefinitionLoader身影。

代码语言:javascript
复制

而在GenericApplicationContext我们又发现了BeanFactory,因此也就是说

annotationConfigServletWebServerApplicationContext已经包含了一切。

了解了这些,我们从prepareContext中开始寻找load的真谛。

我们看到在prepareContext中BeanDefinitionLoader,其中的rources就是我们的启动了,registry就是我们的annotationConfigServletWebServerApplicationContext。但是我们在springApplication中就已经通过createApplicationContent创建了BeanDefinitionLoader,这里为啥要重新创建?

代码语言:javascript
复制
    protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
        return new BeanDefinitionLoader(registry, sources);
    }
代码语言:javascript
复制
    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }

看样子是要做一下处理了。我们看到这里的loader其实是new出来的,并不是从content中拿取的,因为我们最终还是要将bean注册到content中的beanfactory中,因此看的出来,这里采用new的方式更像是被看做工具。因为并不会影响content中注册的bean的最终目的。

我们进去laod方法

代码语言:javascript
复制
    public int load() {
        int count = 0;
        //这里的resource就是我们上边createBeanDefinitionLoader方法传入的
        //启动类
        Object[] var2 = this.sources;
        int var3 = var2.length;
        for(int var4 = 0; var4 < var3; ++var4) {
            Object source = var2[var4];
            count += this.load(source);
        }
        return count;
    }

我们看看这里的this.load(source);正好就是咋那会儿看的根据不同类型的传入参数进行不同的load方法。

显然我们传入的是class。那么我们就进入第一个方法。

这块采用的注解的reader进行注册。

为了更好的理解这个reader,我们有必要看一下他的初始化方法。看到最后发现了很长的一段代码。我们就传入了content,没想到居然有那么复杂的逻辑。那么这块到底是干啥的?看着这么多的代码有没有感到恐惧。

代码语言:javascript
复制
  public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {
      //从content中获取beanfactory

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
        //设置依赖比较器,解析@Order和@Priority
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);  
      }
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
        //设置bean的@Autowired解析器
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
    }

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    //如果我们的content中没有包含 ConfigurationClassPostProcessor那就注册到content中
    //这里的ConfigurationClassPostProcessor是一个后置处理器 
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
//如果没有AutowiredAnnotationBeanPostProcessor处理器,那就注册进去
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
//注册CommonAnnotationBeanPostProcessor
    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
//
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition();
      try {
        def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
            AnnotationConfigUtils.class.getClassLoader()));
      }
      catch (ClassNotFoundException ex) {
        throw new IllegalStateException(
            "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
      }
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }
//EventListenerMethodProcessor的注册
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
      RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }
    return beanDefs;
  }

通过上述的代码详解,我们发现初始化AnnotatedBeanDefinitionReader的时候居然做了那么多工作。但是这里有一个特别重要的概念:后置处理器。

我们看看它怎么工作的

我们来手动实现一个,然后看看有什么蛛丝马迹

代码语言:javascript
复制
@Component
public class MyAppTest implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

        System.out.println("注册bean");
        //这里的BeanDefinitionRegistry应该就是content
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        //这里就是bean工厂

        System.out.println("这里是工厂");
    }
}

启动测试项目

发现实现了该接口的方法的类,会在bean容器加载结束,bean实例化之前进行调用。那么如果定义多个这样的类是不是会每个都执行一下?咋继续测试一下。发现还真实这么一回事。那么就好理解上边哪些后置处理器了。因为我们可以看到在这个接口的入参都是重量级元素,那可是可以轻松的获取所有bean的呀,所以相当于说可以对其进行各种操作。上边注册的哪些后置处理器其实就是用来解析的。解析结束之后就可以实例化了。是不是发现这个接口非常好?我目前是这样想的。但是至于在哪里去掉这个接口,我想应该在我们之前分析的那个核心方法中。就是refresh中。这个后期咋再突破。

看的出来,这个loader.load()目前来说就只把启动类注册到了content中了。那么其他的类是在那块逻辑中会被注册进来?我想是在那些后置处理器中。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员备忘录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档