结构
Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:
AnnotationConfigApplicationContext 是基于注解来使用的,它不需要配置文件,采用 java 配置类和各种注解来配置,是比较简单的方式,也是趋势,我倾向使用这种方式。
BeanFactory 简介
BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。最终的默认实现类是 DefaultListableBeanFactory。
为何要定义这么多层次的接口:他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。
1 | public interface BeanFactory { |
IOC构造初始化
Spring的Ioc的初始化过程,实际上就是把beanName和BeanDefinition注册到DefaultListableBeanFactory的map中。
使用注解的方式创建代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
Spring中出来注解Bean定义的类有两个: AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext。
AnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本,两者的用法以及对注解的处理方式几乎没有什么差别
AnnotationConfigApplicationContext构造方法如下:
1 | public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry { |
主要属性:
AnnotatedBeanDefinitionReader——BeanDefinition解析器用来解析带注解的bean
ClassPathBeanDefinitionScanner——bean的扫描器 用来扫描类
注册解析传入的配置类(使用类配置的方式进行解析)
调用容器的refresh方法初始化容器
1、注册BeanDefinition的注册器
1 | /** |
2、注册扫描器
1 | public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, |
扫描注册
1 | public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { |
this()方法,会去初始化AnnotatedBeanDefinitionReader读取器和ClassPathBeanDefinitionScanner扫描器
如果传入类,最终会执行到:
1 | <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, |
如果是个包名
1 | public int scan(String... basePackages) { |
具体扫描操作
1 | protected Set<BeanDefinitionHolder> doScan(String... basePackages) { |
findCandidateComponents(basePackage)方法,这个方法里就是具体的扫描逻辑。
1 | public Set<BeanDefinition> findCandidateComponents(String basePackage) { |
这里是扫描逻辑,主要过程:
根据包路径,扫描所有.class文件
根据包路径,生成.class对应的Resource对象
通过ASM获取class元数据,并封装在MetadataReader元数据读取器中
判断该类是否符合过滤规则
判断该类是否为独立的类、具体的类
加入到集合中
1 | private Set<BeanDefinition> scanCandidateComponents(String basePackage) { |
这里最主要的是isCandidateComponent判断规则
1 | //判断元信息读取器读取的类是否符合容器定义的注解过滤规则@CompoentScan的过滤规则支持5种 (注解、类、正则、aop、自定义) |
通过 isCandidateComponent(metadataReader),在这个方法中 有 tf.match(metadataReader, getMetadataReaderFactory())
Spring就是这样发现@Configuration、@Controller、@Service这些注解修饰的类的。过滤方法:
1 | //是否是独立的类、具体的类 |
这个方法的作用是,判断该类是否为:顶层的类(没有父类或静态内部类)、具体的类(不是抽象类或接口)
类型封装
1 | protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { |
处理内部类
1 | protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) |
至此包扫描也结束了,已经把扫描到的类存入到了集合中,结下来就是解析注册Bean的过程了。
bean实例化
注册的主要方法:
1 | public void refresh() throws BeansException, IllegalStateException { |
准备工作
1 | //做一些准备工作,记录容器的启动时间、标记“已启动”状态、检查环境变量等 |
BeanFactory的初始化、Bean的加载和注册等事件
1 | ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); |
准备工厂,设置BeanFactory的类加载器、bean表达式解释器等一些初始化操作,添加几个 BeanPostProcessor、手动注册几个特殊的bean。
1 | /** |
在spring的环境中去执行已经被注册的 后置工厂处理器
1、getBeanFactoryPostProcessors()得到自己定义的(就是 没有交给spring管理,没有加上@Component)
2、得到spring内部自己维护的BeanDefinitionRegistryPostProcessor
1 | protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { |
循环所有的BeanDefinitionRegistryPostProcessor,该方法内部postProcessor.postProcessBeanDefinitionRegistry
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
1 | public static void invokeBeanFactoryPostProcessors( |
调用扩展方法postProcessBeanDefinitionRegistry
1 | public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { |
拿出的所有bd,然后判断bd时候包含了@Configuration、@Import,@Compent。。。注解
1 | public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { |
1、的到bd当中描述的类的元数据(类的信息)
2、判断是不是加了@Configuration metadata.isAnnotated(Configuration.class.getName())
3、如果加了@Configuration,添加到一个set当中,把这个set传给下面的方法去解析
1 | public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { |
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)
1 | public void parse(Set<BeanDefinitionHolder> configCandidates) { |
注册beanPostProcessor(registerBeanPostProcessors(beanFactory);)
注意不是BeanFactoryPostProcessor,此接口有两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization分别会在Bean初始化之前和初始化之后得到执行。
1 | public static void registerBeanPostProcessors( |
初始化当前 ApplicationContext 的 MessageSource
1 | protected void initMessageSource() { |
初始化应用事件广播器
1 | protected void initApplicationEventMulticaster() { |
初始化其他
1 | // TODO:扩展点 比如初始化其他特殊的bean |
完成此上下文的bean工厂的初始化,初始化所有剩余的单例bean。
1 | protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { |
发布事件
1 | protected void finishRefresh() { |
Bean的加载
refresh()还调用了很多后处理器的方法,其中有一个方法 finishBeanFactoryInitialization(),意味着非延迟加载的类,将在这一步实例化,完成类的加载。
当我们显示或者隐式地调用 BeanFactory#getBean(String name) 方法时,则会触发加载 Bean 阶段。
1 |
|
1 | protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, |
#doGetBean(…) 方法的代码量比较多,可以看出 bean 的加载过程是一个非常复杂的过程,会涉及到各种各样的情况处理。
可以分为以下几个过程:
- 转换 beanName,方法传入的 name 并不一定就是 beanName,可以传入 aliasName,FactoryBean,所以这里需要进行简单的转换过程。
- 尝试从缓存中加载单例 bean。
- bean的实例化。
- 原型模式的依赖检查。Spring只会解决单例模式的循环依赖,对于原型模式的循环依赖都是直接抛出 BeanCurrentlyInCreationException 异常。
- 尝试从 parentBeanFactory 获取 bean 实例。如果 parentBeanFactory != null && !containsBeanDefinition(beanName) 则尝试从 parentBeanFactory 中获取 bean 实例对象,因为 !containsBeanDefinition(beanName) 就意味着定义的 xml 文件中没有 beanName 相应的配置,这个时候就只能从 parentBeanFactory 中获取。
- 获取 RootBeanDefinition,并对其进行合并检查。从缓存中获取已经解析的 RootBeanDefinition 。同时,如果父类不为 null 的话,则会合并父类的属性。
- 依赖检查。某个 bean 依赖其他 bean ,则需要先加载依赖的 bean。
- 对不同的 scope 进行处理。
- 类型转换处理。如果传递的 requiredType 不为 null,则需要检测所得到 bean 的类型是否与该 requiredType 一致。如果不一致则尝试转换,当然也要能够转换成功,否则抛出 BeanNotOfRequiredTypeException 异常。
获取原始beanName
1 | protected String transformedBeanName(String name) { |
从缓存中获取单例bean
1 | //单例bean的缓存 |
该方法就是从 singletonObjects、earlySingletonObjects、 singletonFactories 三个缓存中获取,这里也是 Spring 解决 bean 循环依赖的关键之处。
第一步,从singletonObjects中获取Bean对象
第二步,如果获取不到且Bean正在创建中,从earlySingletonObjects获取Bean对象
第三步,如果获取不到且允许提前创建,从singletonFactories获取FactoryBean
第四步,如果不为null,则通过FactoryBean.getObject()获取Bean,然后将其加入到 earlySingletonObjects ,并且从 singletonFactories 删除,两者是互斥的,主要用来解决循环依赖的问题
创建 bean 实例对象
如果缓存中没有,也没有 parentBeanFactory ,则会调用 #createBean(String beanName, RootBeanDefinition mbd, Object[] args) 方法,创建 bean 实例。
1 | // AbstractBeanFactory.java |
抽象方法的默认实现是在类 AbstractAutowireCapableBeanFactory 中实现,该方法其实只是做一些检查和验证工作,真正的初始化工作是由 #doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 方法来实现。
1 | protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) |
实例化 bean
如果缓存中没有 BeanWrapper 实例对象或者该 bean 不是 singleton,则调用 createBeanInstance方法创建 bean 实例。
1 | protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { |
属性填充
属性填充其实就是将 BeanDefinition 的属性值赋值给 BeanWrapper 实例对象的过程。
1 | protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { |
初始化 bean
1 | protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { |
从 bean 实例中获取对象
无论是从单例缓存中获取的 bean 实例 还是通过 createBean() 方法来创建的 bean 实例,最终调用getObjectForBeanInstance()方法,来获取最终的Bean实例。
1 | //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理 |
当该实例对象为非 FactoryBean 类型,直接返回给定的 Bean 实例对象 beanInstance 。当该实例对象为FactoryBean 类型,从 FactoryBean ( beanInstance ) 中,获取 Bean 实例对象。
getObjectFromFactoryBean
1 | //Bean工厂生产Bean实例对象 |