首先,本系列并不是以介绍spring5 的新特性为主,之所以以spring5为标题,是因为即将赏析的源码来自最新的spring版本.虽说是spring最新版本,但是容器的整个生命周期与之前版本相比,并没有很大的变化,我们主要来看spring是如何一步步构建自己的容器,一步步将混乱不堪,错综复杂的依赖关系管理的井井有条,一步步组建自己的spring帝国.

因为篇幅原因,并不能在一篇博客中将所有spring容器的内容都介绍完成,因此,将分为几个部分分别介绍,本篇会先从最顶层浏览一下spring的一些容器,以及spring抽象出的容器的组装过程,使我们对spring容器有一个整体上的认知.

  先来介绍spring中几个重要的接口的作用:

1.BeanFactory

2.BeanDefinition

3.BeanDefinitionRegistry

4.ApplicationContext

先看BeanFactory,这个接口定义了所有beanfactory基础功能: 根据名称获取bean,获取bean的类型/别名,判断bean是否存在等,可以看到,所有实现了这个接口的类,都具备这个功能.
BeanDefinition,定义了容器管理的对象.这个接口是整个spring的核心.BeanDefinition可以看做spring的领域模型,它是对所有bean统一建模的产物,涵盖了bean的所有信息,所有注册进spring容器的bean均会被处理成各种beanDefinition的实现
存储起来.
BeanDefinitionRegistry定义了beanDefinition的注册功能.实现了这个接口的类,具备了注册beandefinition的能力,将组装好的beandefinition注册到容器中。

最后看ApplicationContext,这个是容器的接口,所有容器均实现了这个接口,它定义了容器的基本功能:获取容器名,获取父容器,获取beanfactory,注册bean,等等,来看一下继承关系:

我们发现它继承许多接口,这意味着实现这个接口的类,必须具备它所实现的所有类的功能,当然,这些功能正真实现的地方不会在application的实例中,这里用到了代理模式(百度),将主要职责委托给其它实现接口的类去做,将调用者和实现者解耦,使代码具备良好的扩展性。

spring的容器有多种,我把它分两大类:应用类和web类。

应用类中常用的几个容器:

AnnotationConfigApplicationContext  (主要是注解驱动,spring3.0以后加入)
GenericXmlApplicationContext   (也是3.0以后加入的,可以作为下面两种的替代。相对与相面两个容器来说比较灵活,可以灵活设置xml)
ClassPathXmlApplicationContext  (和下面的容器基本一样,一个是类路径加载(主要特色是能加载jar中的xml文件),一个是文件路径加载。两者实现基本一样,所以会有GenericXmlApplicationContext的出现)
FileSystemXmlApplicationContext
web类的常用容器:
基本与上面一一对应,这里就简单列举一些:
AnnotationConfigWebApplicationContext
GenericWebApplicationContext
XmlWebApplicationContext

了解上面的基本概念以后,我们就要开始spring容器的探索之旅了,因为考虑到web容器还要考虑servlet版本,以及web.xml的配置,相对于应用容器来说稍微复杂一些。所以这次我们并不会以支持web容器为例去分析。
最近,springboot比较火爆(默认配置就是使用AnnotationConfigApplicationContext容器),我们就来看看AnnotationConfigApplicationContext这个容器,看它是如何把一个个注解都转化为自己认识的bean并管理起来,
并为我们提供各种各样的服务。(其实几个容器的底层实现都一样,毕竟是同一个爸生的。。。)
先看一个简单的栗子:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Level1Config.class);
context.refresh();
Level2Component l = (Level3Component) context.getBean("level2Component");
l.asd();
@Configuration
@ComponentScan("org.springframework.context.annotation.componentscan.level2")
public class Level1Config {
@Bean
public TestBean level1Bean() {
return new TestBean("level1Bean");
}
}
@Component
public class Level2Component {
@Autowired
SimpleComponent simpleComponent;
public void asd(){
simpleComponent.testq();
} }
@Component
public class SimpleComponent { public void testq(){
System.out.println("asdf");
} @Bean
public String exampleBean() {
return "example";
} }

这个栗子中,spring扫描了“org.springframework.context.annotation.componentscan.level2”包,装载了里面的Level2Component和SimpleComponent等,并将SimpleComponent实例化赋值给Level2Component,然后我们就可以通过context获取到Level2Component的实例,并调用SimpleComponent的方法。

我们看到从context的声明到bean实例被调用,只经过了4行代码,可谓简单至极,但在这背后却做了我们想象不到的许多事。

在深入源码之前,我们最好先从最顶层看一下它的架构,然后带着问题去看,这样才能有目的性的找到答案和学到东西,废话不多说,先看一下spring是如何装配AnnotationConfigApplicationContext的,个人总结如下:

准备 ——>初始化容器——>扫描装配beanDefinition(这里只是初步装配)——>组装实例化bean

因此,本系列也会分成四部分和大家一起来鉴赏各个流程的代码。

这里就先来介绍相对简单的一步:准备。

准备阶段,spring主要是为容器初始化一些bean,将一些配置文件读取,扫描器,beanfacotry,bean的一些默认处理工具类实例化并装配起来,看一下构造函数:

    public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

还有它父类的构造函数:

    public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}

按照类初始化的顺序,我们可以看到,这里初始化了resourcePatternResolver,beanfactory,annotationBeanDefinitionReader,classPathBeanDefinitionScanner,这几个类,这些类的作用分别是:资源定位解析,定义bean容器,注解类解析,类路径资源扫描。它们的详细实现在后续讨论中依然会出现,这里我们只详细关注AnnotationBeanDefinitionReader,这个类,因为这个类参与了准备阶段的工作。

先看一下构造函数:

    public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
ConditionEvaluator是@Conditional注解的解析的实现类,这里我们重点看

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
} Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4); 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));
} 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));
} if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
} // 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));
} 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被实例化的时候spring洋洋洒洒注册了一堆bean,这些bean将在以后我们有新的bean加入的时候起关键性作用,比如改变bean的行为,比如监听发布事件,比如解析一个外部定义的配置类,等等,这些bean在后面的分析中均会一一出现,这里同样不做全面介绍,我们只要知道,这些bean实在这个时候就已经被spring装载进来了。

我们继续往下看:

接着就是注册我们自定义的bean了.
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}

在我们register配置类的时候reader(即AnnotationBeanDefinitionReader)的register方法会被调用,进而会调用它的doRegisterBean方法,将配置类注入容器中:

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
} abd.setInstanceSupplier(instanceSupplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
} BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

按照顺序,首先我们可以看到,配置类会被放到AnnotatedGenericBeanDefinition中:

public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}

annotationGenericBeanDefinition实例会持有StandardAnnotationMetadata的实例,StandardAnnotationMetadata顾名思义,它是封装了这个类的注解的元数据。接着,spring会判断是否符合Condition注解的条件(spring4的加进来的一个注解),接下来会解析scope注解,来确定这个bean的作用域,接下来会调用processCommonDefinitionAnnotations方法处理一些常规的注解:@Primary,@DependsOn,@Rule.@Description,并将这些信息放入定义好的beanDefinition中,接着通过BeanDefinitionReaderUtils将beanDefinition注册到容器里。至此算是容器中的第一个我们自己的bean就注册完成。

我们看到,register方法实际上就是将配置类中一些我们不长用注解信息解析并放入beandefinition中,将注解元数据放入StandardAnnotationMetadata中,由beanDefinition持有,最终把beanDefinition放入容器中(beanFactory),并没有发生什么不得了的事情,我们定义的注解类也只是初步解析,并没有进行扫描或者注入其它bean,事实上,在bean的准备阶段,spring确实没做多少事情,而是将一些十分重要的bean一一初始化进容器中,而我们自定义的配置类就是其中之一。

好了,第一阶段就到这里。第一阶段准备阶段,spring实例化了一个reader,并在实例化过程中装载了annotationConfigApplicationContext容器特有的bean的处理逻辑,随后把我们的配置类也装载进去变完成了准备阶段的工作。

转载请注明出处。

spring5之容器始末源码赏析 (一)总览的更多相关文章

  1. spring 事务源码赏析(二)

    我们在spring 事务源码赏析(一) 中分析了spring事务是如何找到目标方法,并如何将事务的逻辑织入到我们的业务逻辑中.本篇我们将会看到spring事务的核心实现: 1.事务传播机制的实现 2. ...

  2. spring 事务源码赏析(一)

    在本系列中,我们会分析:1.spring是如何开启事务的.2.spring是如何在不影响业务代码的情况下织入事务逻辑的.3.spirng事务是如何找到相应的的业务代码的.4.spring事务的传播行为 ...

  3. Cocos2dx源码赏析(1)之启动流程与主循环

    Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者 ...

  4. Cocos2dx源码赏析(4)之Action动作

    Cocos2dx源码赏析(4)之Action动作 本篇,依然是通过阅读源码的方式来简单赏析下Cocos2dx中Action动画的执行过程.当然,这里也只是通过这种方式来总结下对Cocos2dx引擎的理 ...

  5. Cocos2dx源码赏析(3)之事件分发

    Cocos2dx源码赏析(3)之事件分发 这篇,继续从源码的角度赏析下Cocos2dx引擎的另一模块事件分发处理机制.引擎的版本是3.14.同时,也是学习总结的过程,希望通过这种方式来加深对Cocos ...

  6. Cocos2dx源码赏析(2)之渲染

    Cocos2dx源码赏析(2)之渲染 这篇,继续从源码的角度来跟踪下Cocos2dx引擎的渲染过程,以此来梳理下Cocos2dx引擎是如何将精灵等元素显示在屏幕上的. 从上一篇对Cocos2dx启动流 ...

  7. Java源码赏析(五)再识 String 类

    在 Java源码赏析(三)初识 String 类   中,我们已经大概理解了String的接口,接下来我们描述一下String的常用工具方法. /** * 为了精简的String结构,之前提到的方法省 ...

  8. Java源码赏析(三)初识 String 类

    由于String类比较复杂,现在采用多篇幅来讲述 这一期主要从String使用的关键字,实现的接口,属性以及覆盖的方法入手.省略了大部分的字符串操作,比如split().trim().replace( ...

  9. Java源码赏析(六)Class<T> 类

    目的 Class 类是每一个程序员都必须了解的,也是使用反射机制的基础. 这篇文章将Class 类的公共方法大致介绍了一遍(省略了安全.枚举.断言.注解相关代码). 代码 package java.l ...

随机推荐

  1. jdbc里一个最靠谱的连接demo

    最靠谱的jdbc连接例子 包括增删改,查一条数据,查所有数据. Bean.java public class Bean { private String id; private String numb ...

  2. Javascript学习笔记-基本概念-语法、关键字和保留字、变量

    语法 1.区分大小写 2.标识符 所谓标识符,就是指变量.函数.属性的名字,或者函数的参数. 命名规则: 第一个字符必须是一个字母.下划线(_)或一个美元符号($): 其他字符可以是字母.下划线.美元 ...

  3. 先导篇:SpringCloud介绍篇

    1.什么是SpringCloud Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中心.消息总线.负载 ...

  4. py面向对象编程基础

    '''类:一类事物的抽象,用于定义抽象类型 实例:类的单个实际描述 如:人是一个类,而单个人是一个实例 用class来创建一个类,调用一个类来创建一个实例'''class Person: passxi ...

  5. 工作技术点小计14条 hybrid + animate 方向

    设置transition 动画的时候 , js直接设置duration 和 变化值不会起作用 , 需要先设置duration , 等一小会再设置变化值 安卓端 , 窗口不可见时 , window.in ...

  6. HTML5中form的新增属性或元素

    1.新增的表单元素 1.1 progress表示任务的完成情况,常用于进度条. max 定义进度元素所要求的任务的工作量,默认值为1 value 定义已经完成的工作量,如果max值为1,该值必须是介于 ...

  7. 利用virtualenvwrapper创建虚拟环境出现错误“/usr/bin/python: No module named virtualenvwrapper”

    Linux:CentOS7 python: 系统默认python版本2.7,利用python启动 自己安装python版本3.8,利用python3启动 问题描述: 在上述环境中利用virtualen ...

  8. Python基础-两个乒乓球队进行比赛,各出三人。

    两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人.已抽签决定比赛名单.有人向队员打听比赛的名单.a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单. L1 = [ ...

  9. 纯C 实现 strpos substr strspilt str_trim

    在C 语言中没有C++ 好用的 spilt 方法 (STL 带的也不怎么好用) #include <stdio.h> #include <string.h> #include ...

  10. Java反射之Class类

    接下来的几章,我们谈一谈java的反射机制. 反射就是从一个java类中映射出一个java类或是一个实例.通常在很多框架中都用到反射,比如常用的ssm框架,在配置文件中总是会写到类的全名,框架通过读取 ...