Spring资源(Resource)与工厂(Factory)创建流程

232 阅读3分钟

从宏观上梳理它的核心组件

Spring对于Bean管理的核心组件:

  1. 资源抽象 (Resource)
  2. 工厂 (Factory)
  3. 配置信息读取器 (BeanDefinitionReader)

大致阅读一下Spring源码

BeanFactory

  • 是一个接口 image.png

用于访问 Spring bean 容器的根接口
这是 bean 容器的基本客户端视图; 其他实现它的接口,如ListableBeanFactory和org.springframework.beans.factory.config.ConfigurableBeanFactory可用于特定目的。

  • 该接口有一些方法

image.png

  • BeanFactory是Spring Bean工厂最顶层的抽象,其地位,类似于Java中的Object类。

  • DefaultListableBeanFactory类的UML图 image.png

Resource

  • 是一个接口 image.png

从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口。

BeanDefinitionReader

  • 是一个接口 image.png

bean 定义读取器的简单接口。使用资源和字符串参数指定加载方法

从微观上梳理它的核心组件

  • 再次提及之前写的代码
    public class SpringClient {
      public static void main(String[] args) {
          Resource resource = new ClassPathResource("applicationContext.xml");
          DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
          BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(factory);
          beanDefinitionReader.loadBeanDefinitions(resource);
          // 解析 装配Bean
          // =================================================
          // 加载Bean
          Student student = (Student) factory.getBean("student");
          System.out.println(student.getName() +"\n" + student.getAge());
      }
    }
    
    

深入解读资源(Resource)的创建

ClassPathResource

有涉及JVM的一些知识。
JVM 类加载器 - 掘金 (juejin.cn)
JVM 线程上下文类加载器 - 掘金 (juejin.cn)

  • 功能说明 image.png

类路径资源的Resource的实现。 使用给定的ClassLoader给定的Class来加载资源

  • 成员变量 image.png

功能说明已经指出:使用给定的ClassLoader给定的Class来加载资源*,所以有这些成员变量。

  • 构造方法是重点

image.png image.png

image.png

  • 小结
    • path需要删除前导斜杠。
    • 成员变量Class和ClassLoader选其一即可。
    • ClassPathResource类的源码看下来,其实它本质就是想调用ClassLoader类提供的getResource()也可以是getResourceAsStream(),又或者是,Class类提供的getResourceAsStream(),但是本质还是基于ClassLoader类提供的getResouce(); image.png
    • 只要得到ClassLoader,差不多就可以得到Resource了。
    • Resource其实就是URL。
  • 看了它的源码突发奇想,请勿模仿,来让ClassPathResource找不到资源
    • 众所周知,jdk提供3个原始的类加载器,BootStrap、Ext、System类加载器,每个类加载器都只加载特定路径上的类。
    • ExtClassLoader只加载jre/lib/*下面的类。我们自己写的项目肯定不在jre目录下面。它肯定加载不了
    • 所以改变一下当前线程上下文类加载器。
    public class SpringClient {
      public static void main(String[] args) {
          ClassLoader classLoader = ClassLoader.getSystemClassLoader();
          classLoader = classLoader.getParent();//获取类加载器的父类加载器,即ExtClassLoader
          Thread.currentThread().setContextClassLoader(classLoader);//改变线程上下文类加载器
          System.out.println(classLoader);
    
          Resource resource = new ClassPathResource("applicationContext.xml");
          DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
          BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(factory);
          beanDefinitionReader.loadBeanDefinitions(resource);
    
          Student student = (Student) factory.getBean("student");
          System.out.println(student.getName() +"\n" + student.getAge());
      }
    
    }
    
    image.png

深入解读工厂(Factory)的创建

DefaultListableBeanFactory

  • 构造方法

image.png

  • 其父类构造方法中还有一个方法,ignoreDependencyInterface(Class arg)

image.png

简单说,忽略Spring提供的一些设施,不要使用一些特定设施来识别依赖注入。

  • *Aware***
    • aware,翻译过来是知道的,已感知的,意识到的,所以这些接口从字面意思应该是能感知到所有Aware前面的含义。
    • 先举个BeanNameAware的例子,实现BeanNameAware接口,可以让该Bean感知到自身的BeanName(对应Spring容器的BeanId属性)属性。 image.png

    由Bean实现该接口,让bean 在bean 工厂中能感知自己的名字。 请注意,通常不建议对象依赖于其 bean 名称,因为这表示对外部配置的潜在脆弱依赖,以及对 Spring API 的可能不必要的依赖。

    • 同理,其他的Aware接口也是为了能够感知到自身的一些属性。比如实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象。实现了BeanClassLoaderAware接口的类,能够获取到加载该bean的ClassLoader对象。

    bean自己都能得到(知道)自己想要的依赖了,还要Spring干嘛。

    • 也就是说,在进行依赖注入时,AbstractAutowireCapableBeanFactory,不希望通过这些Aware方式进行依赖注入。可能有不好的后果,具体是什么?
      • 鄙人猜测,应该是不想依赖注入的方式过于丰富,不想让bean自己完成自己的依赖注入,而应该由Spring自己完成。

配置信息读取器 (BeanDefinitionReader) 下回分解