Spring源码篇-ApplicationContext

  前面通过手写IoC,DI、AOP和Bean的配置。到最后ApplicationContext的门面处理,对于Spring相关的核心概念应该会比较清楚了。接下来我们就看看在Spring源码中,对于的核心组件是如何实现的。

一、ApplicationContext

  ApplicationContext到底是什么?字面含义是应用的上下文。这块我们需要看看ApplicationContext的具体的结构。

  通过ApplicationContext实现的相关接口来分析,ApplicationContext接口在具备BeanFactory的功能的基础上还扩展了 应用事件发布,资源加载,环境参数国际化的能力。然后我们来看看ApplicationContext接口的实现类的情况。

  在ApplicationContext的实现类中有两个比较重要的分支 AbstractRefreshableApplicationContextGenericApplicationContext.

二、BeanFactory

  上面分析了 ApplicationContext接口的结构。然后我们来看看 BeanFactory在ApplicationContext中具体的实现是怎么样的

可以看到具体的实现是 DefaultListableBeanFactory .然后我们来看看他的体系结构

BeanFactory的继承体系

三、BeanDefinition

  然后我们来了解下ApplicationContext是如何来加载Bean定义的。具体代码我们需要分为XML配置文件和基于注解的两种方式来看。

1.基于XML方式

  我们先定义对应的application.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="beanE" class="com.study.spring.sample.config.BeanE" /><bean id="beanF" class="com.study.spring.sample.config.BeanF" ></bean><context:annotation-config/><context:component-scan base-package="com.study.spring.sample.config" ></context:component-scan></beans>

然后我们的测试类代码

public class XMLConfigMain {public static void main(String[] args) {ApplicationContext context = new GenericXmlApplicationContext("classpath:com/study/spring/sample/config/application.xml");BeanF bf = context.getBean(BeanF.class);bf.do1();}
}

处理的过程 解析XML --> BeanDefinition --> BeanDefinitionRegistry --> BeanFactory

2.基于注解方式

  然后来看看基于注解方式的使用的情况。首先是我们的配置类

@Configuration
@ComponentScan("com.study.spring.sample.config")
public class JavaBasedMain {@Beanpublic BeanH getBeanH() {return new BeanH();}public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(JavaBasedMain.class);BeanH bh = context.getBean(BeanH.class);bh.doH();}
}

然后是我们的测试类

public class AnnotationMain {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext("com.study.spring.sample.config");BeanG bg = context.getBean(BeanG.class);bg.dog();}
}

注解使用有两种方法:

  1. 配置扫描路径
  2. 配置@Configuration的注解类

2.1 this构造方法

  在this的构造方法中会完成相关的配置处理。

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

首先是AnnotatedBeanDefinitionReader(this)方法。会完成核心的ConfigurationClassPostProcessor的注入。ConfigurationClassPostProcessor 会完成@Configuration相关的注解的解析

this.scanner其实就是创建了一个对应的扫描器

2.2 扫描实现

  扫描就需要进入到scan方法中。

完成相关的注册

2.3 @Configuration

  @Configuration的解析其实是在refresh方法中来实现的。

3.小结

  通过上面的分析其实我们已经对Bean定义的扫描,解析和注册过程有了一定的了解。归纳为:

  1. reader解析XML,完成xml方法配置的bean定义
  2. scanner扫描指定包下的类,找出带有@Component注解的类,注册成Bean定义
  3. 通过ConfigurationClassPostProcessor对带有@Configuration注解的类进行处理,解析它上面的注解,以及类中带有@Bean 注解,加入这些的Bean的定义。

4.BeanDefinition

  ;然后我们来看看BeanDefinition的继承结构

  继承属性访问器和元数据接口,增加了Bean定义操作,实现了数据和操作解耦。属性访问器和元数据接口接着往下看。

4.1 BeanMetadataElement

  BeanMetadataElement提供了获取数据源的方式,也就是可以指导Bean是来自哪个类。

public interface BeanMetadataElement {/*** Return the configuration source {@code Object} for this metadata element* (may be {@code null}).*/@Nullabledefault Object getSource() {return null;}}

4.2 BeanMetadataAttribute元数据属性

  实现了元数据接口,增加了属性的名字和值。。


public class BeanMetadataAttribute implements BeanMetadataElement {private final String name;@Nullableprivate final Object value;@Nullableprivate Object source;}

4.3 AttributeAccessor属性访问器

  AttributeAccessor用来给Bean定义了增删改查属性的功能

public interface AttributeAccessor {/*** Set the attribute defined by {@code name} to the supplied {@code value}.* If {@code value} is {@code null}, the attribute is {@link #removeAttribute removed}.* <p>In general, users should take care to prevent overlaps with other* metadata attributes by using fully-qualified names, perhaps using* class or package names as prefix.* @param name the unique attribute key* @param value the attribute value to be attached*/void setAttribute(String name, @Nullable Object value);/*** Get the value of the attribute identified by {@code name}.* Return {@code null} if the attribute doesn't exist.* @param name the unique attribute key* @return the current value of the attribute, if any*/@NullableObject getAttribute(String name);/*** Remove the attribute identified by {@code name} and return its value.* Return {@code null} if no attribute under {@code name} is found.* @param name the unique attribute key* @return the last value of the attribute, if any*/@NullableObject removeAttribute(String name);/*** Return {@code true} if the attribute identified by {@code name} exists.* Otherwise return {@code false}.* @param name the unique attribute key*/boolean hasAttribute(String name);/*** Return the names of all attributes.*/String[] attributeNames();}

4.4 AttributeAccessorSupport属性访问抽象实现类

  内部定义了1个map来存放属性。

public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {/** Map with String keys and Object values. */private final Map<String, Object> attributes = new LinkedHashMap<>();@Overridepublic void setAttribute(String name, @Nullable Object value) {Assert.notNull(name, "Name must not be null");if (value != null) {this.attributes.put(name, value);}else {removeAttribute(name);}}//  ......
}

4.5 BeanMetadataAttributeAccessor元数据属性访问器

  继承AttributeAccessorSupport具备属性访问功能,实现BeanMetadataElement具备获取元数据功能。 **AbstractBeanDefinition就继承于它,使得同时具有属性访问和元数据访问的功能 **。

结合AbstractBeanDefinition.来看看他们的类图结构

5. BeanDefinition继承体系

5.1 AnnotatedBeanDefinition

  增加了2个方法,获取bean所在类的注解元数据和工厂方法元数据,这些数据在进行解析处理的时候需要用到。

public interface AnnotatedBeanDefinition extends BeanDefinition {/*** Obtain the annotation metadata (as well as basic class metadata)* for this bean definition's bean class.* @return the annotation metadata object (never {@code null})*/AnnotationMetadata getMetadata();/*** Obtain metadata for this bean definition's factory method, if any.* @return the factory method metadata, or {@code null} if none* @since 4.1.1*/@NullableMethodMetadata getFactoryMethodMetadata();}

  该注解有三个具体的实现。ScannedGenericBeanDefinition、AnnotatedGenericBeanDefinition、ConfigurationClassBeanDefinition。

5.2 AbstractBeanDefinition模板类

  AbstractBeanDefinition我们可以称之为BeanDefinition的模板类。结构我们上面其实有梳理

  通过上面我们可以看到AbstractBeanDefinition 具备了 Bean元数据的获取和属性相关的操作。同时AbstractBeanDefinition的继承结构

5.3 RootBeanDefinition根bean定义

  它主要用在spring内部的bean定义、把不同类型的bean定义合并成RootBeanDefinition(getMergedLocalBeanDefinition方法)。没有实现BeanDefinition接口的设置获取父bean定义方法,不支持设置父子beanDefinition。

5.4 ConfigurationClassBeanDefinition

  用作ConfigurationClassPostProcessor解析过程中封装配置类的bean定义。

5.5 GenericBeanDefinition

  GenericBeanDefinition通用Bean的定义。

5.6 ScannedGenericBeanDefinition

  @ComponentScan扫描的bean定义使用。

5.7 AnnotatedGenericBeanDefinition

【06】Spring源码-分析篇-ApplicationContext相关推荐

  1. Spring源码分析篇(一)之Gradle环境搭建

    Gradle的简介我就不在此多废话了,我们直接上步骤 本人的操作环境是mac jdk1.8+spring5.x版本 编译工具:IDEA IntelliJ 一.熟悉你需要的spring源码包 这个源码包 ...

  2. Spring 源码分析, ApplicationContext build 包找不到编译异常

    instrument 包 aop-test 包 content 包 ...等 这是博主的 gradle 文件 dependencies {compile(project(":spring-b ...

  3. Spring 源码分析衍生篇十三 :事务扩展机制 TransactionSynchronization

    文章目录 一.前言 二.TransactionSynchronization 1. TransactionSynchronization 1.1 TransactionSynchronization ...

  4. Spring 源码分析衍生篇三 : lookup-method 和 replaced-method

    文章目录 一.前言 二.基本使用 1. 作用 三.原理实现 1. 预处理 1.1 AbstractBeanDefinition#prepareMethodOverrides 1.2 Autowired ...

  5. Spring 源码分析衍生篇十 :Last-Modified 缓存机制

    文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...

  6. spring源码分析之spring-core总结篇

    1.spring-core概览 spring-core是spring框架的基石,它为spring框架提供了基础的支持. spring-core从源码上看,分为6个package,分别是asm,cgli ...

  7. Spring源码分析系列——bean创建过程分析(三)——工厂方法创建bean

    前言 spring创建bean的方式 测试代码准备 createBeanInstance()方法分析 instantiateUsingFactoryMethod()方法分析 总结 spring创建be ...

  8. Spring 源码分析 (一)——迈向 Spring 之路

    一切都是从 Bean 开始的 在 1996 年,Java 还只是一个新兴的.初出茅庐的编程语言.人们之所以关注她仅仅是因为,可以使用 Java 的 Applet 来开发 Web 应用.但这些开发者很快 ...

  9. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

最新文章

  1. bzoj2326 [HNOI2011]数学作业
  2. ipv6 端口号_计算机网络之IP、MAC、端口号、子网掩码、默认网关、DNS
  3. HTML与CSS基础之子元素的伪类(七)
  4. 再有人问你MySql的隔离级别,直接把这篇文章发给他!
  5. hdata datax交流总结
  6. Cannot find executable for CFBundle 解决办法
  7. 2015英特尔® 实感™ (Intel® RealSense™) 动手开发实验课
  8. java插件开发_编写一个IDEA插件之:自动生成Java代码
  9. python运行界面黑色_在Python中使用open执行轮廓检测后,如何使图像的背景变黑?...
  10. EXCEL制作行政区地图,小O地图EXCEL版发布新版本
  11. 用井字游戏理解 Minimax 算法
  12. 在华为做测试员是一种什么体验?带你深入了解华为
  13. 《卫星与网络》分析孙宇晨为什么选择蓝色起源
  14. UE4TTS文字转语音功能。
  15. Redis 中的 集合(Set) SCARD:获取集合包含的元素数量
  16. 英语面试自我介绍java_java面试英语自我介绍
  17. [SugerTangYL] Verilog 语言入门(零基础视角)
  18. css3中的属性选择器以及新增伪类
  19. JavaScript 判断是否是数字 isFinite() Number.isFinite()
  20. 加入企业黄页有什么好处?

热门文章

  1. 轮询,长连接,长轮询原理及实现方式,优缺点
  2. 总结编译Liblas库时的问题(会及时更新解决博友遇到的问题)
  3. sprint2的总结及团队贡献分
  4. FreeMarker数值数据处理问题
  5. python打印运行log
  6. Excel如何将数据拆分开
  7. 在Linux中,_exit()、exit(0)、exit(1)、和return的区别!!
  8. SQL 全文检索应用
  9. dds:core:policy
  10. 【神经网络】正向传播和反向传播(结合具体例子)