从宏观上梳理它的核心组件
Spring对于Bean管理的核心组件:
- 资源抽象 (Resource)
- 工厂 (Factory)
- 配置信息读取器 (BeanDefinitionReader)
大致阅读一下Spring源码
BeanFactory
- 是一个接口
用于访问 Spring bean 容器的根接口。
这是 bean 容器的基本客户端视图; 其他实现它的接口,如ListableBeanFactory和org.springframework.beans.factory.config.ConfigurableBeanFactory可用于特定目的。
- 该接口有一些方法
-
BeanFactory是Spring Bean工厂最顶层的抽象,其地位,类似于Java中的Object类。
-
DefaultListableBeanFactory类的UML图
Resource
- 是一个接口
从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口。
BeanDefinitionReader
- 是一个接口
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)
- 功能说明
类路径资源的Resource的实现。 使用给定的ClassLoader或给定的Class来加载资源。
- 成员变量
功能说明已经指出:使用给定的ClassLoader或给定的Class来加载资源*,所以有这些成员变量。
- 构造方法是重点
- 小结
- path需要删除前导斜杠。
- 成员变量Class和ClassLoader选其一即可。
- ClassPathResource类的源码看下来,其实它本质就是想调用ClassLoader类提供的getResource()也可以是getResourceAsStream(),又或者是,Class类提供的getResourceAsStream(),但是本质还是基于ClassLoader类提供的getResouce();
- 只要得到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()); } }
深入解读工厂(Factory)的创建
DefaultListableBeanFactory
- 构造方法
- 其父类构造方法中还有一个方法,ignoreDependencyInterface(Class arg)
简单说,忽略Spring提供的一些设施,不要使用一些特定设施来识别依赖注入。
- *Aware***
aware
,翻译过来是知道的,已感知的,意识到的,所以这些接口从字面意思应该是能感知到所有Aware
前面的含义。- 先举个
BeanNameAware
的例子,实现BeanNameAware
接口,可以让该Bean
感知到自身的BeanName
(对应Spring容器的BeanId
属性)属性。
由Bean实现该接口,让bean 在bean 工厂中能感知自己的名字。 请注意,通常不建议对象依赖于其 bean 名称,因为这表示对外部配置的潜在脆弱依赖,以及对 Spring API 的可能不必要的依赖。
- 同理,其他的
Aware
接口也是为了能够感知到自身的一些属性。比如实现了BeanFactoryAware
接口的类,能够获取到BeanFactory
对象。实现了BeanClassLoaderAware
接口的类,能够获取到加载该bean的ClassLoader
对象。
bean自己都能得到(知道)自己想要的依赖了,还要Spring干嘛。
- 也就是说,在进行依赖注入时,
AbstractAutowireCapableBeanFactory
,不希望通过这些Aware方式进行依赖注入。可能有不好的后果,具体是什么?鄙人猜测,应该是不想依赖注入的方式过于丰富,不想让bean自己完成自己的依赖注入,而应该由Spring自己完成。