美文网首页Spring-Boot
Spring 之 IoC 源码分析 (基于注解方式)

Spring 之 IoC 源码分析 (基于注解方式)

作者: 7e86aaa7b08a | 来源:发表于2019-08-19 13:55 被阅读21次

    一、 IoC 理论

    IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。

    二、IoC方式

    Spring为IoC提供了2种方式,一种是基于xml,另一种是基于注解。

    <Bean>标签来定义bean,进行管理。

    @Bean注解来定义bean,进行管理。

    本次文章我们就来分析下基于注解的IoC原理,在看文章之前我们可以带一些疑问,这样有助于我们更好的理解。

    @Bean是干什么用的?

    @Controller、@Service又是干啥的?

    @CompoentScan注解是怎么起作用的?

    Spring是怎么发现@Bean、@Controller、@Service这些注解修饰的类的?

    发现之后是怎么注册到IOC容器中的?

    IOC容器到底是个啥?

    三、源码分析

    首先看下段代码:

    AnnotationConfigApplicationContext可以实现基于Java的配置类(包括各种注解)加载Spring的应用上下文。避免使用application.xml进行配置。相比XML配置,更加便捷。

    3.1、类结构图

     主要类或接口说明:

    GenericApplicationContext——通用应用上下文,内部持有一个DefaultListableBeanFactory实例,这个类实现了BeanDefinitionRegistry接口,可以在它身上使用任意的bean definition读取器。典型的使用案例是:通过BeanFactoryRegistry接口注册bean definitions,然后调用refresh()方法来初始化那些带有应用上下文语义(org.springframework.context.ApplicationContextAware)的bean,自动探测org.springframework.beans.factory.config.BeanFactoryPostProcessor等。

    BeanDefinitionRegistry——用于持有像RootBeanDefinition和 ChildBeanDefinition实例的bean definitions的注册表接口。DefaultListableBeanFactory实现了这个接口,因此可以通过相应的方法向beanFactory里面注册bean。GenericApplicationContext内置一个DefaultListableBeanFactory实例,它对这个接口的实现实际上是通过调用这个实例的相应方法实现的。

    AbstractApplicationContext——ApplicationContext接口的抽象实现,没有强制规定配置的存储类型,仅仅实现了通用的上下文功能。这个实现用到了模板方法设计模式,需要具体的子类来实现其抽象方法。自动通过registerBeanPostProcessors()方法注册BeanFactoryPostProcessor, BeanPostProcessor和ApplicationListener的实例用来探测bean factory里的特殊bean——对比1分析

    AnnotationConfigRegistry——注解配置注册表。用于注解配置应用上下文的通用接口,拥有一个注册配置类和扫描配置类的方法。

    3.2 构造函数

    主要属性:

    AnnotatedBeanDefinitionReader——BeanDefinition解析器用来解析带注解的bean

    ClassPathBeanDefinitionScanner——bean的扫描器 用来扫描类

    注册解析传入的配置类(使用类配置的方式进行解析)

    调用容器的refresh方法初始化容器

    这里我们用的是最后一种构造函数,即传入一个包路径。

    3.3 IoC 之 构造函数初始化

    首先看step1,调用了本类的无参构造函数:

    然后初始化AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner

    我们来看下ClassPathBeanDefinitionScanner的构造函数

    继续跟踪下去,最后调用的是这个方法:

    这里面最主要的是registerDefaultFilters()方法,初始化spring扫描默认过滤规则,对应@ComponentScan注解,如果没有自定义规则,就初始化默认过滤规则。

    这里调用的是ClassPathScanningCandidateComponentProvider类中的registerDefaultFilters()方法:

    这里面有两个关键变量:

    private final List<TypeFilter> includeFilters = new LinkedList<>();

    private final List<TypeFilter> excludeFilters = new LinkedList<>();

    includeFilters表示要包含的注解,即只有包含includeFilters中的注解,才会被扫描

    excludeFilters表示要排除的注解,即包含excludeFilters中的注解不会被扫描

    在这个方法中,includeFilters集合中添加了@Component、JavaEE6的@ManagedBean和JSR-330的@Named注解

    而excludeFilters集合没做任何变动,即没有要排除的注解

    总结:

    所以默认规则就是,只要包含了@Component、JavaEE6的@ManagedBean和JSR-330的@Named这3个注解中的任意一个,就会被扫描

    相关文章

      网友评论

        本文标题:Spring 之 IoC 源码分析 (基于注解方式)

        本文链接:https://www.haomeiwen.com/subject/lopssctx.html