1. IOC 概述
    IOC: Inversion of Control(控制反转), 这里其实指的是: 将程序中需要使用的 POJOs, 丢入到容器中, 解析成统一的 BeanDefinition(主要基于XML的 GenericBeanDefinition/RootBeanDefinition 与 通过 注解生成的 ScannedGenericBeanDefinition), 而 Bean 依赖的信息都在XML中描述(或通过注解描述), 容器则负责 Bean 的统一生成(本来Bean的创建/销毁是由我们开发人员控制的), 因此造成了 Bean 的创建/销毁由Bean容器控制的反转现象!(通过下图理解一下)

图中角色:

  1. 如上图 Spring IOC 容器使用了 Configuration Metadata, Configuration Metadata 告知 Spring容器如何去实例化, 配置和装配对应的对象
  2. Configuration Metadata(及 BeanDefinition)现在主要由解析XML.Properties 或通过扫描指定目录下带有特定
  1. IOC 主要组件 BeanDefinition 的属性
    先看一下 BeanDefinition 主要属性
// Bean 的Class 对象
private volatile Object beanClass;// bean 的作用范围, 对应 bean 属性 scope (常见的就是单例/原型)
private String scope = SCOPE_DEFAULT;// 是否是抽象, 来自 bean 属性的 abstract(抽象的类是不能直接生成对象)
private boolean abstractFlag = false;// 是否延迟加载, 对应 bean 属性 lazy-init (值是否在使用 Bean的时候才正真的创建 Bean)
private boolean lazyInit = false;// 自动注入模式, 对应 bean 属性 autowire (这个属性主要指 XML 描述的 beanDefinition, 在生成bean的对吼阶段, 获取容器中的对象, 自动装配在 BeanDefinition 对应的 Field 上)
private int autowireMode = AUTOWIRE_NO;// 依赖检查, Spring 3.0 后 弃用这个属性
private int dependencyCheck = DEPENDENCY_CHECK_NONE;// 用来表示一个 bean 的实例化依靠另一个 bean 先实例化(PS: 这个很少使用了)
private String[] dependsOn;/***  autowire-candidate 属性设置为 false, *  这样容器在查找自动装配对象时*  将不考虑该 bean, 即它不会被考虑作为其他 bean *  自动装配的候选者, 但是该 bean *  本身还是可以使用自动装配来注入其他的 bean*/
private boolean autowireCandidate = true;// 自动装配时当出现多个 bean 候选者时, 将作为首候选者 (PS: 使用比较少)
private boolean primary = false;// 用于记录 Qualifier, 对应子元素 qualifier(当使用 @Autowired 时, 有多个候选Bean 时, 就通过这个Qualifier 来进行区分)
private final Map<String, AutowireCandidateQualifier> qualifiers =new LinkedHashMap<String, AutowireCandidateQualifier>(0);// 允许访问非公开的构造器和方法, 程序设置  (PS: 用得比较少)
private boolean nonPublicAccessAllowed = true;/*** 是否以一种宽松的模式解析构造函数, 默认 true* 如果是 false, 则在如下情况* interface ITest()* class ITestImpl implement ITest();* class Main {*     Main(ITest i) {}*     Main(ITestImpl i) {}* }* 抛出异常, 因为 Spring 无法准确确定哪个构造函数* 程序设置** lenient 宽大, 仁慈*/
private boolean lenientConstructorResolution = true;/*** 对应 bean 属性 factory-bean 用法 (PS: 这里涉及 FactoryBean 这个概念, 这个类主要是解决: 创建一个类, 但创建这个类的过程比较长/条件比较多, 这时候就使用同一的抽象工厂模式(FactoryBean对象) 来创建对象)* <bean id="instanceFactoryBean" class="example.chapter3.InstanceFactoryBean />* <bean id="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime" />*/
private String factoryBeanName;// 对应 bean 属性 factory-method
private String factoryMethodName;// 记录构造函数注入属性, 对应 bean 属性 constructor-arg
private ConstructorArgumentValues constructorArgumentValues;// 普通属性集合 (在XML 中定义Bean的信息时, 通常propertyValues里面有很多依赖信息)
private MutablePropertyValues propertyValues;// 方法重写的持有者, 记录 lookup-method, replaced-method 元素(PS: 与此对应有注解Loopup, 但运用的比较少了)
private MethodOverrides methodOverrides = new MethodOverrides();// 初始化方法, 对应 bean 属性 init-method (PS: 通过 实现InitializingBean 接口, 可以达到同样效果)
private String initMethodName;// 销毁方法, 对应  bean 属性 destory-method (PS: 与之对应的是 DisposableBean, 一帮都是在这类方法中完成资源释放之类的操作)
private String destroyMethodName;// 是否执行 init-method, 程序设置  (默认是 true)
private boolean enforceInitMethod = true;// 是否执行 destory-method, 程序设置 (默认是 true)
private boolean enforceDestroyMethod = true;// 是否是用户定义的而不是应用程序本身定义的, 创建 AOP 部分组件时为 true(见 ConfigBeanDefinitionbeanParser.parseAdvice 方法)
private boolean synthetic = false;/*** 定义这个 bean 的应用, APPLICATION: 用户, INFRASTRUCTURE(infrastructure 基础设施): 内部使用, 与用户无关, SUPPORT: 某些复杂配置的一部分程序设置, 一般都是 BeanDefinition.ROLE_APPLICATION;*/
private int role = BeanDefinition.ROLE_APPLICATION;// bean 的描述信息
private String description;// 这个 bean 定义的资源 (其实就是 A.class 这个文件)
private Resource resource;

PS: 属性好多, 一直其实上面属性中相对重要的有一下几个

  • 2.1 class(该实例化的 Bean), name(bean的命名)

  • 2.2 scope(定义Bean的生命周期)

  • 2.3 constructor arguments(Bean构造函数依赖注入的属性)

  • 2.4 properties(Bean依赖注入的属性, 这里的 properties 主要还是指XML或properties里面描述的信息)

  • 2.5 autowiring mode(是否自动装配, 若是的话, 则容器会在整个容器中寻找所有符合条件的 Field)

  • 2.6 lazy-initialization mode (是否 lazy 生成Bean, 指是否在正真需要使用 Bean时才会创建bean, 但现在运用中一般都是使用 ApplicationContext 的子类, 这个类会在 refresh()
    方法里面中调用 finishBeanFactoryInitialization(), 然后再调用
    preInstantiateSingletons 来实例化容器中的所有类),

  • 2.7 initialization method
    (Spring 容器中 bean 的初始化方法, 这个完全可以通过实现接口 InitializingBean 来实现)

  • 2.8 destruction method (Spring 容器中 bean 的销毁方法, 这个也完全可以通过实现接口 DisposableBean 来实现)

  • PS: 这个有个漏掉的点: 在Spring 创建 Bean的过程中, 容器里面的 BeanFactoryPostProcessor
    可以对Bean的元数据进行一定的修改

  1. IOC 主要组件 BeanDefinition 的分类
    BeanDefinition 其实是根据 BeanDefinition 的收集策略来进行分类的, 主要分成下面:
  1. GenericBeanDefinition: 一个标准的 BeanDefinition, 通过XML 读取Bean的描述信息组装的BeanDefinition一般都是GenericBeanDefinition, 后续的beanDefinition 都是在这个类的基础上进行扩展
  2. ScanedGenericBeanDefinition: 这个类扩展于 GenericBeanDefinition, 底层是通过 ASM 的ClassReader 来获取对应注解 Annotation 相关的元数据
  3. AnnotatedGenericBeanDefinition: 这个 BeanDefinition 与上面的ScanedGenericBeanDefinition 很相似, 都具有 bean上注解的描述信息,AnnotatedGenericBeanDefinition 这个类主要是在使用AnnotationConfigApplicationContext创建容器时, 通过 AnnotationBeanDefinitionReader 来获取对应 BeanDefinition 时创建的
  1. IOC 主要组件 BeanDefinitionReader 概述

先看一下接口BeanDefinitionReader 的主要方法

// beanDefinition 的读取者
// 这里有个注意点, BeanDefinition 的读取器不一定非要实现BeanDefinitionReader接口, 其实这里指的就是 AnnotatedBeanDefinitionReader 与 ClassPathBeanDefinitionScanner
public interface BeanDefinitionReader {// 这里的 BeanDefinitionRegistry 其实就是 beanFactory 的注册接口, BeanDefinition 通过这个接口注入到 BeanFactory 看一下 BeanDefinitionRegistry 的实现类就知道了BeanDefinitionRegistry getRegistry();// ResourceLoader 代表的是 BeanDefinitionReader 需要读取的是 描述BeanDefinition的资源文件加载器, 以前 BeanFactory 与 ResourceLoader 是分离开的两个组件, 后来出现了 ApplicationContext, 将 beanFactory 与 ResourceLoader 结合到一个类中ResourceLoader getResourceLoader();// 加载类的 ClassLoaderClassLoader getBeanClassLoader();// bean 的命名生成器BeanNameGenerator getBeanNameGenerator();// 加载指定目录Resource下 BeanDefinition 的方法int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;// 加载多个指定目录Resource下 BeanDefinition 的方法int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;// 加载指定目录Resource下 BeanDefinition 的方法int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;// 加载多个指定目录Resource下 BeanDefinition 的方法int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}

上面方法定义了获取 BeanDefinition的主要生成策略, 但其中有个重要的点, 就是 BeanDefinition 的读取器不一定非要实现 BeanDefinitionReader 接口, 比如 AnnotatedBeanDefinitionReader(直接注入带注解的bean) 与 ClassPathBeanDefinitionScanner(扫描指定目录下面带注解的Bean)

  1. IOC 主要组件 BeanDefinitionReader 分类
    BeanDefinitionReader 首先是通过一个抽象类 AbstractBeanDefinitionReader 来定义了加载 beanDefinition 的模板方法(模板模式), 接下来根据在不同文件(XML/Properties)中定义Bean描述信息来实现不同类别的 BeanDefinitionReader(策略模式)
  1. AbstractBeanDefinitionReader: 实现 beanDefinitionReader 接口的抽象类, 主要定义了加载类的主逻辑, 后续的类依据不同存储文件不同格式, 有不同的具体实现类
  2. PropertiesBeanDefinitionReader: 读取 properties 文件的 beanDefinitionReader, 这个类相对简单, 但是没有下面的 XMLBeanDefinitionReader 扩展性那么好
  3. GroovyBeanDefinitionReader: 这个类是基于 XMLBeanDefinitionReader 实现的 BeanDefinitionReader
  4. XmlBeanDefinitionReader: 最常见的 BeanDefinitionReader, 也是相对扩展性最好的 Reader(PS: 它的扩展性主要体现在自定义命名空间, 比如 <mvc...>, <aop...>, <tx...>, 或者dubbo扩展的 <dubbo....>)
  5. AnnotatedBeanDefinitionReader: 虽然没有实现 BeanDefinitionReader 接口, 但是它其实还是个 BeanDefinitionReader, 主要是当使用基于注解驱动的
    AnnotationConfigApplicationContext 时使用的
  6. ClassPathBeanBeanDefinitionScanner: 这个类也没有实现BeanDefinitionReader , 但是它非常强大, 知道指定一个扫描的目录, 就会将符合条件的Bean生成 ScanedGenericBeanDefinition 对象,注入到容器中(PS: 当Spring的XML文件中定义了 context:component-scan 也会创建这个类,并且通过这个类扫描指定目录项目的类, 并registry 到 BeanFactory 中) 上面额几种beanDefinitionReader中, XmlBeanDefinitionReader,
    AnnotatedBeanDefinitionReader, ClassPathBeanBeanDefinitionScanner
    是比较重要的, 也是最常见的
  1. IOC 主要组件 Resource 概述
    Resource: Spring 里面对资源进行封装的统一抽象接口, 里面定义了一些通用的方法, 详情如下:
// Spring 中资源的统一抽象接口
public interface Resource extends InputStreamSource {// 返回的资源是否存在boolean exists();// 返回的资源是否可读boolean isReadable();// 返回这个资源是否有已打开流的处理, 若果是 true, 则此 InputStream 就不能被多次读取, 而且只能被读取和关闭以免资源泄露boolean isOpen();// 转换 Resource 到 URLURL getURL() throws IOException;// 转换 Resource 到FileFile getFile() throws IOException;// 返回资源内容的长度long contentLength() throws IOException;// 资源上次修改时间long lastModified() throws IOException;// 创建资源相对于这个资源Resource createRelative(String relativePath) throws IOException;// 对的这个资源的名字String getFilename();// 返回资源的描述, 用于错误处理中打印的信息String getDescription();
}

上面是资源抽象的统一接口, 而针对资源获取的不同方式, 对应的有相应的子类(PS: AbstractResource 是其对应的抽闲子类, 其间定义了一些抽象的方法, 所有的子类都是从这个类派生出来)

  1. IOC 主要组件 Resource 类别

在 Spring 中针对获取资源的不同渠道, 创建了相应的 Resource(主要是依据 路径的格式不同, 来创建不同类别的 Resource), 其中有我们进行开发中常用的一些类, 如下:

  1. FileSystemResource: 比如使用容器 FileSystemXmlApplicationContext时, 配置的 XML 资源都会被封装成FileSystemResource
  2. ServletContextResource: 若是用 XmlWebApplicationContext 系列的 ApplicationContext 容器时, 一般都是生成这个(PS: 这时是以 "/" 开头)
  3. ClassPathResource: 当使用 ClassPathXmlApplicationContext 时, 最终将资源包装成 ClassPathResource(则对应的资源将通过 ClassLoader 进行加载)(PS: 这时是以 "/" 或"classpath:"开头, 若不是的话, 则封装成 URLResource)

PS: 在上面创建 Resource时, 若遇到 Classpath*: 开头时, 则将通过 PathMatchingResourcePatternResolver 来进行获取对应资源, 这时又会判断是否路径中含有 “*/?” 这种字符串, 则获取能正则匹配成功的所有文件;

补充: classpath*: 代表的是获取当前ClassLoader对应的 URLClassPath下面的所有包中匹配的资源(包括父ClassLoader, 详情见PathMatchingResourcePatternResolver.getResources(String locationPattern) ); 而 classpath 则是通过Class.getResourceAsStream(String path) 来获取一个数据流, 对滴就一个文件(详情见 ClassPathResource.getInputStream())

  1. IOC 主要组件 ResourceLoader 概述
    ResourcceLoader 中定义了获取Spring中统一资源的方法, 它将根据路径的前缀来生成对应的 Resource, 其中最通用的就是下面这几种:
  1. DefaultResourceLoader: 这个类是 AbstractApplicationContext 的超类, 其间定义了获取 Resourcce的默认方法 getResource(String location); 若路径以"/"开头, 则交由子类创建对应的
    Resource(根据不同的子类类别创建不同的 Resource, 如
    FileSystemXmlApplicationContext的FileSystemResource,
    GenericWebApplicationContext 的 ServletContextResource,
    ClassPathXmlWebApplicationContext的ClassPathResource), 若路径以
    “classpath:” 开头, 则创建 ClassPathResource, 若不是以上两种情况, 则直接创建 UrlResource
  2. PathMatchingResourcePatternResolver: 这个类是在创建 AbstractApplicationContext 时默认创建的 ResourceResolver, 当遇到的路径是以
    "classpath*: " 开头是就通过这个类来获取 ClassLoader的classpath下面的所有 jar
    中的符合条件的XML资源(PS: PathMatchingResourcePatternResolver是一个非常重要的类,
    而且它获取资源的方式非常直接借鉴)
  1. IOC 主要组件 BeanDefinitionDocumentReader
    这个类存在的意义主要是封装成 XML文件为 Document, 并且根据每个节点的命名空间获取对应的 Namespacehandler 来进行处理解析对应的节点; 其默认实现就是 DefaultBeanDefinitionDocumentReader; 对于普通的命名空间 “http://www.springframework.org/schema/beans”, 则直接用 BeanDefinitionParserDelegate的parseBeanDefinitionElement来进行解析; 若遇到其他命名空间的, 则通过NamespaceHandlerResolver 来获取对应的 NamespaceHandler 来进行解析
    (PS: NamespaceHandler 也是通过META-INF/Spring.handlers 下面定义的命名空间对应的Namespacehandler, 并通过反射来进行创建, 具体看 DefaultNamespacehandlerResolver 的gethandlerMappings )

  2. IOC 主要组件 NamespaceHandler
    Spring解析XML 时, 主要依据命名空间来选择对应的 NamespaceHandler 来进行解析

  1. http://www.springframework.org/schema/beans 对应 默认的解析类 BeanDefinitionParserDelegate
  2. 当遇到其他命名空间时, 则通过 DefaultNamespaceHandlerResolver.resolve(namespaceUri) 来获取对应的
    NamespaceHandler 来进行解析(比如遇到 <mvc…>, <aop…>, <tx…>, 或者 dubbo
    中的)

DefaultNamespaceHandlerResolver 通过获取所有 “META-INF/spring.handlers” 里面定义的 Namespacehandler, 并找到namespace与之对应的进行解析

  1. IOC 主要组件 BeanFactoryPostProcessor
    BeanFactoryPostProcessor: 对这个名词进行分割; BeanFactoryPostProcessor = BeanFactory(bean工厂) + Post(后) + Processor(处理器); 这样就好理解了!
public interface BeanFactoryPostProcessor {// 这个方法在 BeanFactory 加载好所有的 Bean 信息到容器后, 实例化任何Bean实例之前(Bean在容器中有实例化(Instantiation)与初始化(Initialization)的差别, 这点很重要)void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

对于这个类, 最常见的就是用于修改 Bean 的属性, 比如一开始在对应属性上面设置 “${}” 设置这样的占位符, 然后通过对应类进行赋值

  1. BeanFactoryPostProcessor: 定义了方法执行的入口(在加载所有Bean信息到容器之后)
  2. PropertiesLoaderSupport: Properties加载/解析的方式方法
  3. PropertyResourceConfigurer: 继承PropertiesLoaderSupport,
    实现BeanFactoryPostProcessor接口, 其中定义执行方法的主逻辑, 并留下模板方法
    processorProperties(), 留给子类去实现
  4. PropertyOverrideConfigurer: 这个类主要在
    properties 文件里面写入 beanName.fieldname=fieldvalue 这样的键值对来进行解析数据
  5. PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer:
    这两个类都是继承PropertyResourceConfigurer, 但与PropertyOverrideConfigurer不同的是,
    这两个类都是通过"${}" 这种占位符号来确定哪个数据需要替换成 Properties 里面的数据, 其中还涉及到了非常有效的工具类
    PlaceholderResolver(这个类是来获取对应数据中所有的 ${} 中的数据, 其中涉及到递归获取,
    这种获取的方式其实很值得借鉴), 当然还有我们熟悉的设计模式 --> 观察者模式, 通过 BeanDefinition 的观察者
    BeanDefinitionVisitor 来进行 visitor 每一个
    BeanDefinition中的属性(见BeanDefinitionVisitor)
  1. IOC 主要组件 BeanPostProcessor
    BeanPostProcessor 接口是Spring IOC 中扩展机制的提现, 自己可以在BeanPostProcessor的回调方法中实现 "实例化逻辑, 依赖分析"等;
    它具有以下特定:
  1. 可以在容器中注入多个 BeanPostProcessor, 并且通过 Ordered接口来控制 BeanPostProcessor实现的次序;
  2. BeanPostProcessor 的 postProcessbeforeInitialization方法作用在 bean 的初始化方法(PS: 这里的初始化方法主要是通过xml中配置的, 或者实现 InitializingBean接口而具有的afterPropertiesSet)前面调用, 作用在 Bean 实例化, 并且设置好 XML 中配置的依赖熟悉之后调用(PS:其中包括InstantiationAwareBeanPostProcessr的postProcessPropertyValues 之后
    —> postProcessPropertyValues 主要是将 bean中被 @Autowired,@Resource, @PersistenceContext, @Required 注解修饰属性注入对应的值);而在Spring容器自己提供的几个 BeanPostProcesser的实现类中, 可以看到在 ApplicationContextAwareProcessor 中完成了一下Aware 接口的唤醒
  3. BeanPostProcessor 的 postProcessAfterInitialization方法主要作用在 Bean的初始化方法之后执行(PS: 这时的bean已经实例化,并且进行类依赖注入+Aware接口的唤醒), 对于这个接口,最常见的就是通过这个接口实现对 Bean 的 AOP(PS: 其中涉及到一个 IOC 容器中配置多个 AbstractAutoProxyCreator 的情况, 而其内部通过advisedBeans来判断 Bean 是否已经被 动态代理了);在自动AOP中, 主要有基于命名空间的 AspectJAwareAdvisorAutoProxyCreator 与 基于 @AspectJ注解风格的 AnnotationAwareAspectJAutoProxyCreator
    (PS: 针对这两个类, 在介绍AOP中会详细解析)
  4. InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation: Spring中 bean 的实例化前置处理器, 当系统中配置 customTargetSourceCreators 时, 将通过特定的 TargetSource 来对 Bean 进行动态代理,若类已经被动态代理了, 则相应的也会执行 BeanPostProcessor.postProcessAfterInitialization方法(PS: postProcessAfterInitialization 里面可能有些其他的逻辑需要执行)
  5. InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantion: bean 实例的后置方法, 其主要是控制是否需要将 xml 中配置的 Spring 属性进行注入 + InstantiationAwareBeanPostProcessor.postProcessPropertyValue(PS: postProcessPropertyValue这个方法主要是注入被注解修饰的属性)是否执行, 一般情况就是返回 true
  6. InstantiationAwareBeanPostProcessor 的 postProcessProperty: 这是一个非常重要的方法, 主要完成Bean中被注解注释的属性的注入(比如:AutowiredAnnotationBeanPostProcessor 处理 @Autowired, @Value;RequiredAnnotationBeanPostProcessor处理 @Resource; PersistenceAnnotationBeanPostProcessor处理@PersistenceContext等注解)(PS:SpringMVC 的@RequestMapping 与 事务的 @Transactional 又是不同的处理逻辑)
  7. SmartInstantiationAwareBeanPostProcessor 的 predictBeanType: 预测Class的类型, 当系统中发现无法确定Bean类型,并且存在SmartInstantiationAwareBeanPostProcessor,就会通过这个方法来获取对应的class类型(PS: 这个方法主要的实现在 AbstractAutoProxyCreator里面)
  8. SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors: 预测类的构造函数, 之所以有这个方法, 主要存在 @Lookup 注解(PS: 这个注解很少使用), 这个determineCandidateConstructors方法在实例化 Bean的过程中会被调用具体看
    AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors方法
  9. SmartInstantiationAwareBeanPostProcessor的 getEarlyBeanReference: 预测Bean实例, 在
    AbstractAutoProxyCreator中这个方法与postProcessAfterInitialization中只有一个会执行
    Bean 的代理过程(PS: 这是为什么呢, 看看 earlyProxyReferences就知道了, 两个方法在执行wrapIfNecessary 都会通过 earlyProxyReferences 判断是否已经创建好 AOP 对象); 对于这个getEarlyBeanReference 方法是在 Bean 被提早暴露时才会调用
    举例:
    两个类: class A { B b;}; class B { A a; }; 都注入到 Spring 容器,

    1. XmlBeanDefinitionReader 将描述 A,B两个类的xml 文件读入, 并解析成 BeanDefinition, 然后注入到 DefaultListableBeanFactory中;
    2. DefaultListableBeanFactory 通过 getBean 方法开始实例化这两个类, 在创建 A 的时, 发现A是单例, 其容器允许循环引用, 并且 A 不在 map ->
      singletonsCurrentlyInCreation(表示类是否在创建) 中, 则将 A 包装成 ObjectFactory 类,
      放入单例工厂中, 已备被其他创建的类引用, 而 ObjectFactory 中是通过
      AbstractAutowireCapableBeanFactory.getEarlyBeanReference -->
      SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference -->
      AbstractAutoProxyCreator.getEarlyBeanReference 来暴露创建的动态代理对象
    3. 而在实例化 A 后, 发现 A 依赖于 B(这里的依赖信息可能存在于xml 或通过 @Autowired/@Resource 注解), 则开始创建类 B
    4. 同样在创建类 B 时, 发现 B 依赖于 A, 所以直接通过 earlySingletonObjects 来获取上面提早暴露的 ObjectFactory, 接着会
      AbstractAutowireCapableBeanFactory.getEarlyBeanReference -->
      SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference -->
      AbstractAutoProxyCreator.getEarlyBeanReference 来得到最终暴露出来的 A 对象
      BeanPostProcessor 的分类, 各个子类的作用, 包括 BeanFactory 中如何解决循环引用(只有scope是单例,
      并且依赖不是存在在构造函数中才能解决循环引用) 进行了介绍, 后续会对个别 BeanPostProcessor 详细的解析
  1. IOC 主要组件 FactoryBean
    FactoryBean: Spring容器中某类特定Bean的工厂类(这里其实就涉及到了抽象工厂模式), FactoryBean 充斥着整个IOC容器, 一开始接触 FactoryBean的同学可能不深刻理解这个类的好处, 其实看一下 ProxyFactoryBean(生成动态代理的 FactoryBean), ScheduledExecutorFactoryBean(生成定时线程执行器的 FactoryBean), TransactionProxyFactoryBean(基于目标 Target 生成通过切面控制事务的动态代理类), JobDetailFactoryBean(生成基于 org.quartz.JobDetail 的实例), 就能知道 FactoryBean 主要其实是对于一些创建过程复杂的类进行通过操作的类,

  2. IOC 主要组件 BeanFactory
    BeanFactory: 是Spring IOC 容器的顶层接口, 其中定义了获取Bean的一般接口, 如下:

// Spring 的 Bean 容器最顶层的接口, 定义了 Ioc 容器的基本规范
public interface BeanFactory {// 通过在BeanName名字前面加 & 来获取生成对象的 factoryString FACTORY_BEAN_PREFIX = "&";// 通过 Bean 的名字, 获取对应的实例Object getBean(String name) throws BeansException;// 获取指定名称的 Bean, 其中 requiredType 指的是 Bean的类型<T> T getBean(String name, Class<T> requiredType) throws BeansException;// 获取指定名称的 Bean<T> T getBean(Class<T> requiredType) throws BeansException;// 获取指定名称的 Bean, 其中 args 指的是 构造函数/工厂方法的参数Object getBean(String name, Object... args) throws BeansException;// 获取指定类型的 Bean, 其中 args 指的是 构造函数/工厂方法的参数<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;// 判断容器是否含有 Beanboolean containsBean(String name);// 这个名称对应的 Bean 是否是 singleton 类型boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 这个名称对应的 Bean 是否是 prototype 类型boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 判断指定名称对应的 Bean 是否与 typeToMatch 相匹配(这个方法使用得非常多)boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;// 判断指定名称对应的 Bean 是否与 typeToMatch 相匹配(这个方法使用得非常多)boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;// 获取指定 Name 的 bean 类型(PS: 一个特例, 若遇到 FactoryBean, 则会通过 FactoryBean.getObjectType 来获取最终对象的类型)Class<?> getType(String name) throws NoSuchBeanDefinitionException;// 获得 Bean 的别名String[] getAliases(String name);
}

上面接口主要定义了获取 Bean 的接口, 至于 BeanFactory 的继承(HierachicalBeanFactory), 自动装配(AutowireCapableBeanFactory), 批量获取 bean(ListableBeanFactory) 这些特性都是由子接口进行定义, 如下图:

乍一看, 图中类/接口好复杂, 没事, 我们一层一层梳理:

接口:第一层: BeanFactory:                         这个接口里面定义获取 Bean 的基础方法第二层: HierarchicalBeanFactory:             这个接口定义了获取 parentBeanFactory 的方法(PS: 这里其实也存在着委派机制, 当子BeanFactory 获取不到bean时, 会通过父BeanFactory来进行获取, 但是反过来, 父BeanFactory若获取不到Bean, 则不会再到子BeanFactory中获取, 这种父子BeanFactory形式通常在于: 在 Tomcat的web.xml里面配置 ContextLoaderListener.contextInitialized --> ContextLoader.initWebApplicationContext --> 通过反射直接创建 XmlWebApplicationContext  <-- 这个是 parentBeanFactory, 与之对应的 子BeanFactory 是 由 HttpServletBean.init() --> FrameworkServlet.initServletBean --> FrameworkServlet.initWebApplicationContext --> FrameworkServlet.createWebApplicationContext(这时会将上面的父beanFactory设置到子BeanFactory中)) ListableBeanFactory:                (基于类型)获取容器中所有 BeanNames, 获取被注解注释的 BeanName 等方法AutowireCapableBeanFactory:         这里面定义了, 创建Bean, 自动装配 Bean, 初始化 Bean, 为特定 Bean 解决对应依赖属性的方法第三层: ConfigurableBeanFactory:             增加配置Bean功能的BeanFactory, 这个接口, 继承 SingletonBeanFactory, 具备了注册单例bean的接口, 除此之外 其中还定义了配置 ConversionServere(Spring里面的类型转换器, Spring 默认的是 DefaultConversionService, 主要是完成数据类型的转换器的注册); 配置 BeanPostProcessor(Bean后置处理器)的方法, 销毁 Bean的方法ConfigurableListableBeanFactory:    这个接口里面定义了 preInstantiateSingletons (预实例化Bean的方法), 获取指定名称的 BeanDefinition 的方法等(PS: 这个第三层接口主要是针对第二层接口的功能延伸, 其中 ConfigurableBeanFactory 具备了 注册单例Bean的功能)
实现类:AbstractBeanFactory:                这个类继承了 FactoryBeanRegistrySupport 具备了注册单例+支持FactoryBean的能力, 本身也实现了创建 Bean 的主逻辑(getBean 方法), 并留下了 createBean, getBeanDefinition, containsBeanDefinition 等模板方法AbstractAutowireCapableBeanFactory: 这个类继承了 AbstractBeanFactory 并实现了模板方法 createBean, 并实现了接口 AutowireCapableBeanFactory, 完成了对 BeanPostProcessor 的处理DefaultListableBeanFactory:         这个类是 Spring IOC 里面功能最全的 Bean 容器, 我们常用的 ApplicationContext 都是基本都是在内部有个 DefaultListableBeanFactory(基于 ApplicationContext 继承 BeanFactory, 所以你也可以将这种程序设计方式视为 代理方式)
PS:        一开始看 Spring IOC 时被 BeanFactory 的继承接口给吓住了(哇 这么多的接口继承关系, 层级又是这么多), 结果才发现, 这么多接口中只有第一层与第二层接口之间有明显的扩展, 而下面的接口, 都是逐渐逐渐扩充对应的方法

上面是 BeanFactory 的接口设计及实现, 接口层面主要是3级, 都是对容器功能一点一点的扩充, 而其中 AbstractBeanFactory 设计了创建类的主逻辑(getBean方法), 并且预留了创建类的模板方法(createBean), 而最终的实现类就是 DefaultListableBeanFactory, 工作中常用的:

  1. XmlBeanFactory(基于 XmlBeanDefinitionReader读取xml配置的Bean依赖关系)

  2. XmlWebApplicationContext(用于web容器中的BeanFactory)

  3. ClassPathXmlApplicationContext(通过在 classpath 下面查找指定文件的 BeanFactory)

  4. FileSystemXmlApplicationContext(直接通过文件相对路基获取xml配置文件的 BeanFactory)

  5. AnnotationConfigWebApplicationContext (通过扫描指定目录下面的 class 文件, 并将被特定注解修饰的额类加载到容器中的 BeanFactory)
    都是或多或少的用到 DefaultListableBeanFactory(要是继承, 要么就是将DefaultListableBeanFactory设置为其内部的一个变量)

  6. IOC 总结
    上面简单的介绍了一下 Spring IOC 里面的主要组件, 其中涉及到的组件还是比较多的, 一开始进行看源码时可能被浩瀚的代码给淹没, 从而恐惧, 接着就放弃了(相信很多人都会经历过这几个过程), 当然我也经历过, 当然直到现在自己对 Spring 里面有些细节的东西还不是非常了解, 但其实没关系, 个人觉得只要把握主要的设计思想以及常见的架构设计就可以了!(毕竟全部弄精还是非常耗时的一个工程)

https://www.jianshu.com/p/2e6103f571f1

Spring IOC 组件概述相关推荐

  1. Spring Aop 组件概述

    Spring Aop 概述 AOP(Aspect-Oriented Programming) 面向切面编程, 这种编程模型是在 OOP(Object-Oriented Programming) 的基础 ...

  2. Spring IoC(一)IoC容器的设计与实现:BeanFactory与ApplicationContext

    在写BeanFactory与ApplicationContext 之前,我想先简单聊一聊Spring IoC 容器,希望能给大家一个参考.如果你对这反面的知识比较了解,可以直接跳过. (一)Sprin ...

  3. 小马哥spring编程核心思想_求小马哥讲Spring栈核心编程思想 Spring IoC+Bean+Framework教程...

    这次搜集了下小马哥讲Spring栈核心编程思想 Spring IoC+Bean+Framework,最强Spring全面核心实战的视频教程,有需要的朋友可以自行下载学习. 课程简介: 小马哥出手的Sp ...

  4. Spring IOC和DI概述

    一.IOC和DI 1. IOC (Inversionof Control): 其思想是反转资源获取的方向.传统的资源查找方式要求组件向容器发起资源查找请求.作为回应,容器适时的返回资源. 而应用了IO ...

  5. Spring IOC(一):概述

    参考书籍:<Spring技术内幕> 系列文章 Spring IOC(一):概述 Spring IOC(二):初始化 Spring IOC(三):依赖注入 Spring IOC(四):相关特 ...

  6. 【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】

    每篇一句 基础技术总是枯燥但有价值的.数学.算法.网络.存储等基础技术吃得越透,越容易服务上层的各种衍生技术或产品 相关阅读 [小家Spring]Spring AOP原理使用的基础类打点(AopInf ...

  7. Spring —— IoC 容器详解

    引言 本篇博客总结自官网的<The IoC Container>,其中会结合王富强老师的<Spring揭秘>融入自己的语言和理解,争取通过这一篇文章彻底扫除spring IOC ...

  8. SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)

    微信公众号:吉姆餐厅ak 学习更多源码知识,欢迎关注. SpringBoot2 | SpringBoot启动流程源码分析(一) SpringBoot2 | SpringBoot启动流程源码分析(二) ...

  9. Spring IOC知识点一网打尽!

    前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工厂模式,总 ...

最新文章

  1. matlab能修图吗,相机上这个“功能”,不打开会影响修图效果,别等拍完照片才知道...
  2. CloudStack无法添加模板和iso
  3. java工资高还是php_java和php哪个工资高
  4. Appium Python 六:管理应用和Activity
  5. 2021阿里巴巴大数据技术公开课第一季:外部工具连接SaaS模式云数仓MaxCompute实战
  6. 火焰和烟雾的训练图像数据集_游戏开发者是烟雾和镜子的大师
  7. 【代码笔记】iOS-播放从网络上下载的语音
  8. 浅析Entity Framework Core中的并发处理
  9. spring aop 必须的包 及里面用到的东西_学习Spring的思考框架
  10. C++ 构造函数体内赋值与初始化列表的区别
  11. gnuwin32从全量备份中单表还原_入门MySQL——备份与恢复
  12. 计算混响时间的意义_混响时间的测量方法和步骤
  13. VHDL学习--分频器
  14. 如何在阿里云建立网站
  15. 加息+四巫日铁矿石大跌,棕榈油认沽最高30倍,豆一09-01继续反套2022.6.15
  16. java利用TOTP算法动态生成一次性密码
  17. 大计基作业记录(3)
  18. Day73_Spark核心原理加强
  19. Linux/Unix 设计思想概述
  20. 程序员生存定律-打造属于自己的稀缺性

热门文章

  1. 可重入锁和不可重入锁
  2. 《javascript面向对象编程指南》读书笔记
  3. 自动发送邮件(整理版)
  4. 关于Unity游戏开发方向找工作方面的一些个人看法
  5. VS的几个实用快捷键
  6. PHP漏洞之session会话劫持
  7. JS刷新父窗口的几种方式
  8. PHP连接mysql数据库
  9. 查看关于yum的配置
  10. 神经网络训练细节之batch normalization