Spring如何创建一个对象
首先来看一个类org.springframework.context.support.ClassPathXmlApplicationContext
这个类就是我们一开始使用Spring的时候会首先认识的一个类,在Spring 3的时候增加了一个org.springframework.context.annotation.AnnotationConfigApplicationContext
, 经常使用Spring的人都应该知道第一个类的作用,创建了spring的容器,并指定了扫描路径。其实这两个类的作用基本相同,只不过在一些具体形式上有一些区别,比如前者主要是去读取指定路径下的xml
配置文件,后者则是通过java配置类的形式去配置Spring容器。
1 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml"); |
这里之所以提及AnnotationConfigApplicationContext
,是因为我们目前主流使用的SpringBoot
就是基于这个类来实现的。
通过以上代码后,我们通常就可以使用context
容器对象通过getBean
方法去获取对象,在这个过程中就创建了Bean对象。那接下来就了解Spring是如何创建一个对象的。
那么此处有一个问题可以思考下:通过Spring容器获得的Bean和java中new xxx
得到的bean有什么区别呢?
Spring中bean的创建生命周期
xxx.class
—> 判断使用哪个构造方法 —> 普通对象 —> Aware回调 —> 依赖注入(属性赋值@Autowrite
) —> 初始化前(@PostConstruct
) —> 初始化 ( InitializingBean
)—> 初始化后(AOP) —> AOP之后会生成一个代理对象 —> Bean
- Spring扫描class得到BeanDefinition
- 根据得到的BeanDefinition去生成bean
- 首先根据class推断构造方法
- 根据推断出来的构造方法,反射,得到一个对象(暂时叫做原始对象)
- 填充原始对象中的属性(依赖注入)
- 如果原始对象中的某个方法被AOP了,那么则需要根据原始对象生成一个代理对象
- 把最终生成的代理对象放入单例池(源码中叫做singletonObjects)中,下次getBean时就直接从单例池拿即可
依赖注入
伪代码
1 | // 通过car对象获取其属性,并遍历属性中查找带有Autowired注解的 |
初始化前
@PostConstruct
注解,初始化前调用,可以对bean进行一些赋值工作,使用和依赖注入类似
初始化
判断当前bean是否实现了InitializingBean
, 通过 instance of InitializingBean
判断是否实现接口,实现了该接口后,就将当前bean转换成InitializingBean
对象,然后通过该对象去调用实现接口需要重写的afterPropertiesSet()
方法
Spring源码中对用的位置 AbstractAutowireCapableBeanFactory.initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
1 | public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory |
大致的过程就是上述的,Spring源码中会比这个更多,支持更多的扩展点,比如Aware
、beanPostProcess
,就是spring提供的很多的扩展点,以及一些常见主流款框架如何通过扩展点集成到Spring中,见本站链接
手写Spring
本代码中包含了Spring读取配置文件,实现了@ComponentScan
注解,读取指定路径下的所有文件。读取所有文件下的Component
标记的类。@Scope
注解实现简单的单例bean和原型bean。此处的构造方法使用默认的无参构造方法,并 没有实现复杂判断构造方法的功能。生成普通对象后,实现了简单的BeanNameAware
扩展点,并实现了基于@Autowrited
依赖注入。
实现InitializingBean
接口,在创建bean的时候,如果实现了InitializingBean
接口,会自动执行afterPropertiesSet
方法。
实现BeanPostProcessor
接口,bean的后置处理器,两个默认的方法postProcessBeforeInitialization
、postProcessAfterInitialization
。
理解了bean的创建过程,bean从读取class文件、通过ClassLoader
进行类的加载、创建BeanDefinition
对象、保存类的Scope
属性保存至BeanDefinition
、将BeanDefinition
放入Map缓存中、在获取bean的时候,通过scope不同属性创建bean,并将创建的bean保存至相应的map缓存池中。创建bean的时候实现了依赖注入(属性赋值)、判断Aware
接口、BeanPostProcessor
后置处理器初始化前、InitializingBean
初始化接口、`BeanPostProcessor
后置处理器初始化后。
BeanPostProcessor
类似AOP的实现过程。
此处只贴出了Application
的代码,具体的接口代码就不贴了,那些就是一些注解和接口,很简单,不会的直接从Spring中取一下也可以。
1 | package com.spring; |
总结
BeanPostProcessor
:这属于面向切面的扩展,针对具有默写共同点的类进行统一的扩展。
Aware
:面向实现指定接口的类进行扩展。
InitializingBean
:面向实现指定接口的类进行扩展。
BeanDefinition
表示Bean定义,BeanDefinition
中存在很多属性用来描述一个Bean的特点。通常使用Bean标签(<Bean/>
)、@Bean注解
、@Component(@Service、@COntroller)
等方式来声明一个bean,以上几种方式统称为申明式定义Bean,同时还可以使用编程式定义Bean,在Spring源码中更多的都是通过BeanDefinition
来编程式的创建bean的。
BeanDefinitionReader
Spring源码中提供的BeanDefinition
读取器,这些我们通常不会使用到,但是在Spring源码中使用的很多。AnnotatedBeanDefinitionReader
、XmlBeanDefinitionReader
等。
ClassPathBeanDefinitionScanner
扫描器,作用和BeanDefinitionReader
类似,可以进行扫描,扫描某个包的路径,对扫描到的类进行解析。
BeanFactory
表示Bean工厂,负责创建Bean,并且提供获取Bean的API。IOCbean工厂的顶级接口 定义一系列对bean的操作。
而ApplicationContext
是BeanFactory
的一种,在Spring源码中,是这么定义的:
首先,在Java中,接口是可以多继承的,我们发现ApplicationContext
继承了ListableBeanFactory
和HierarchicalBeanFactory
,而ListableBeanFactory
和HierarchicalBeanFactory
都继承至BeanFactory
,所以我们可以认为ApplicationContext继承了BeanFactory
,ApplicationContext
也是BeanFactory
的一种,拥有BeanFactory
支持的所有功能,不过ApplicationContext
比BeanFactory
更加强大,ApplicationContext
还继承了其他接口,也就表示ApplicationContext
还拥有其他功能,
比如
MessageSource
表示国际化,ApplicationEventPublisher
表示事件发布,EnvironmentCapable
表示获取环境变量,等等,关于ApplicationContext后面再详细讨论。
在Spring的源码实现中,当我们new一个ApplicationContext
时,其底层会new一个BeanFactory
出来,当使用ApplicationContext
的某些方法时,比如getBean()
,底层调用的是BeanFactory
的getBean()
方法。
在Spring源码中,BeanFactory
接口存在一个非常重要的实现类是:DefaultListableBeanFactory
,也是非常核心的。
所以,我们可以直接来使用DefaultListableBeanFactory
,而不用使用ApplicationContext
的某个实现类,比如:1
2
3
4
5
6
7
8DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(User.class);
beanFactory.registerBeanDefinition("user", beanDefinition);
System.out.println(beanFactory.getBean("user"));
DefaultListableBeanFactory
是非常强大的,支持很多功能,可以通过查看DefaultListableBeanFactory
的类继承实现结构来看
它实现了很多接口,表示,它拥有很多功能:
AliasRegistry
:支持别名功能,一个名字可以对应多个别名BeanDefinitionRegistry
:可以注册、保存、移除、获取某个BeanDefinition
BeanFactory
:Bean工厂,可以根据某个bean的名字、或类型、或别名获取某个Bean对象SingletonBeanRegistry
:可以直接注册、获取某个单例BeanSimpleAliasRegistry
:它是一个类,实现了AliasRegistry
接口中所定义的功能,支持别名功能ListableBeanFactory
:在BeanFactory
的基础上,增加了其他功能,可以获取所有BeanDefinition
的beanNames
,可以根据某个类型获取对应的beanNames
,可以根据某个类型获取{类型:对应的Bean}的映射关系HierarchicalBeanFactory
:在BeanFactory
的基础上,添加了获取父BeanFactory
的功能DefaultSingletonBeanRegistry
:它是一个类,实现了SingletonBeanRegistry
接口,拥有了直接注册、获取某个单例Bean的功能ConfigurableBeanFactory
:在HierarchicalBeanFactory
和SingletonBeanRegistry
的基础上,添加了设置父BeanFactory
、类加载器(表示可以指定某个类加载器进行类的加载)、设置Spring EL表达式解析器(表示该BeanFactory
可以解析EL表达式)、设置类型转化服务(表示该BeanFactory
可以进行类型转化)、可以添加BeanPostProcessor
(表示该BeanFactory
支持Bean的后置处理器),可以合并BeanDefinition
,可以销毁某个Bean等等功能FactoryBeanRegistrySupport
:支持了FactoryBean
的功能AutowireCapableBeanFactory
:是直接继承了BeanFactory
,在BeanFactory
的基础上,支持在创建Bean的过程中能对Bean进行自动装配AbstractBeanFactory
:实现了ConfigurableBeanFactory
接口,继承了FactoryBeanRegistrySupport
,这个BeanFactory
的功能已经很全面了,但是不能自动装配和获取beanNames
ConfigurableListableBeanFactory
:继承了ListableBeanFactory
、AutowireCapableBeanFactory
、ConfigurableBeanFactory
AbstractAutowireCapableBeanFactory
:继承了AbstractBeanFactory
,实现了AutowireCapableBeanFactory
,拥有了自动装配的功能DefaultListableBeanFactory
:继承了AbstractAutowireCapableBeanFactory
,实现了ConfigurableListableBeanFactory
接口和BeanDefinitionRegistry
接口,所以DefaultListableBeanFactory
的功能很强大
ApplicationContext
ApplicationContext
是一个接口,实际上也是一个BeanFactory
,不过相较于BeanFactory
更为强大。
HierarchicalBeanFactory
:拥有获取父BeanFactory
的功能ListableBeanFactory
:拥有获取beanNames的功能ResourcePatternResolver
:资源加载器,可以一次性获取多个资源(文件资源等等)EnvironmentCapable
:可以获取运行时环境(没有设置运行时环境功能)ApplicationEventPublisher
:拥有广播事件的功能(没有添加事件监听器的功能)MessageSource
:拥有国际化功能
两个比较重要的实现类
AnnotationConfigApplicationContext
ConfigurableApplicationContext
:继承了ApplicationContext
接口,增加了,添加事件监听器、添加BeanFactoryPostProcessor
、设置Environment
,获取ConfigurableListableBeanFactory
等功能AbstractApplicationContext
:实现了ConfigurableApplicationContext
接口GenericApplicationContext
:继承了AbstractApplicationContext
,实现了BeanDefinitionRegistry
接口,拥有了所有ApplicationContext的功能,并且可以注册BeanDefinition
,注意这个类中有一个属性(DefaultListableBeanFactory
beanFactory
)AnnotationConfigRegistry
:可以单独注册某个为类为BeanDefinition
(可以处理该类上的@Configuration注解,已经可以处理@Bean注解),同时可以扫描AnnotationConfigApplicationContext
:继承了GenericApplicationContext
,实现了AnnotationConfigRegistry
接口,拥有了以上所有的功能
ClassPathXmlApplicationContext
也是继承了AbstractApplicationContext
,但是相对于AnnotationConfigApplicationContext
而言,功能没有AnnotationConfigApplicationContext
强大,比如不能注册BeanDefinition
国际化
(MessageSource)
资源加载
可以直接利用ApplicationContext获得某个文件的内容
获取运行时环境
事件发布
类型转化
在Spring源码中,有可能需要把String转换成其他类型,所以在Spring源码中提供了一些技术来更方便的对对象进行类型转化
PropertyEditor
:JDK中提供的类型转化工具类
ConversionService
:Spring中提供的类型转化服务,比propertyEditor
更强大
TypeConverter
:整合了上面两个功能,Spring源码中使用的
OrderComparator
是Spring所提供的一种比较器,可以用来根据@Order
注解或实现Ordered
接口来执行比较从而进行排序的工具类。
另外,Spring中还提供了一个OrderComparator
的子类:AnnotationAwareOrderComparator
,它支持用@Order
来指定order
值。
BeanPostProcessor
表示Bean的后置处理器,我们可以定义一个或多个BeanPostProcessor
BeanFactoryPostProcessor
表示bean工厂的后置处理器,其实和BeanPostProcessor
类似,BeanPostProcessor
是干涉Bean
的创建过程,BeanFactoryPostProcessor
是干涉BeanFactory
的创建过程。
FactoryBean
上面提到的BeanPostProcessor
是用来干涉Bean
的创建过程,但是如果我们想让一个Bean完全由我们来创建,也是可以的,可以通过FactoryBean
来创建,这样创建出来的bean不会经过完成的Bean的生命周期,只会经过初始化后,其他的依赖注入等是不会经过的。
通过FactoryBean
创建的bean和我们常用的申明式创建的bean主要区别在于是否有完整的Spring的生命周期,自然申明式创建的bean是具备完整的生命周期的。
ExcludeFilter
、IncludeFileter
这两个过滤器是Spring扫描过程中用来过滤的,见名知意,ExcludeFilter
表示排除过滤器,IncludeFileter
表示包含过滤器。
在Spring的扫描逻辑中,默认会添加一个AnnotationTypeFilter
给includeFilters
,表示默认情况下Spring扫描过程中会认为类上有@Component
注解的就是Bean。
MetadataReader
、ClassMetadata
、AnntationMetadata
在Spring中需要取解析类的信息,比如类名、类中的方法、类上的注解等信息,这些都称之为类的元数据,Spring中对上述信息做了一些封装,提供了一些工具类,可以很方便的获取元数据信息。
SimpleMetadataReader
解析类的时候,使用的是ASM技术
为什么要使用ASM技术呢?
Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动的时候就把这些类全部加载进JVM
中,这样不太好,就使用了ASM
扩展:
ASM技术:ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
...
...
Copyright 2021 sunfy.top ALL Rights Reserved