1.spring IOC容器 其实就是 new 了一个 ApplicationContext 类对象。-》应用上下文对象。

2.应用上下文对象 实例化、配置,并管理 bean。

    所以上下文对象是 spring 的核心, 创建对象并把他们连接在一起,管理他们的生命周期。

--------------------

spring容器(应用上下文)通过我们提交的 POJO类 和 配置元数据(你懂得) 产生一个充分配置的(Fulled Configured)可使用的(ready for use)系统。

1.spring创建bean的几个手段(bean就是new好的对象)

--通过@Component, @Service注解的方式 (默认都是通过无参的构造函数来实例化对象)

--通过普通的XML方式(跟@Component注解一个道理)   《顺序:通过<bean>标签的class 属性得到一个class对象;然后通过class对象获取到对应的方法名称的Method对象;最后反射调用Method.invoke(null, args)》

--通过@Configuration注解的方式

--通过@Bean的方式

--通过静态工厂方法 ????? (因为是静态方法,方法在执行时,不需要一个对象)

--通过实例工厂方法的方式 ????

2.依赖注入的两种方式(实例化后的bean对象,注入才能成为spring bean。)

--构造函数注入

--Setter方法注入

通过@Autowire指定使用哪个构造方法(有参无参)或哪个setter方法注入;

  

  首先明确一点,直接添加@Autowire注解到字段上,不需要提供 setter方法 也能完成注入。(spring 会通过反射获取当前Class中的private定义的字段,然后通过反射包的方法,File.set(Class, Privatekey) 这种方式完成注入)

  构造函数注入和setter方法注入可以混用,

    对于一些强制依赖,最好使用构造函数注入,对于一些可选依赖,我们可以采用setter方法注入。

    spring 团队推荐使用 构造函数的方式注入,,但是对于一些构造参数过长的构造函数,spring是 不推荐的。

~方法注入vs依赖注入:

  为什么有了依赖注入,还需要有方法注入的方式呢,方法注入解决了什么问题?   (我也看不懂,不知道)

  -依赖注入:什么是依赖? 一个对象的依赖其实就是自身的属性。spring中的依赖注入其实就是属性注入。

    我们知道一个对象由两部分组成:属性 + 行为。 可以说spring通过属性注入 + 方法注入的方式掌控整个bean。

    属性注入和方法注入都是spring提供给我们用来处理bean之间协作关系的手段。

    属性注入有两种方式:构造函数注入和 setter方法注入。

    方法注入需要依赖动态代理完成。(不是很懂)

    方法注入对属性注入进行了一定程度上的补充,因为属性注入的情况下,原型可能会失去原型的意义(为什么要使用方法注入)

3.  精确注入vs自动注入vs方法注入 (依赖注入又叫‘精确注入’,对应的还有‘自动注入’)

  --自动注入是针对整个对象,或者一整批对象。比如我们如果将autoService这个bean的注入模型设置为byName,spring会为我们去寻找所有符合要求的名字(通过setter方法)bean并注入到autoService 中,

  而精确注入这种方式,是我们针对对象中的某个属性,比如我们在autoService中的dmzService这个属性字段上添加了@AutoWired注解,代表我们要精确的注入dmzService这个属性。

  而方法注入主要是基于方法对对象进行注入。

  --我们通常所说***byName***,***byType***跟我们在前文中提到的注入模型中的byName,byType 完全不一样。通常我们说的***byName***,***byType***是spring寻找bean的手段。比如,当我们注入模型为constructor时,Spring 会先通过名称找符合要求的bean,这种通过名称寻找对应的bean的方式,我们可以成为byName. 我们可以将一次注入分为两个阶段,首先是寻找符合要求的bean,其次再将符合要求的bean注入。

3.1   补充spring1.4小结的剩余部分

  -- depends-on:

    我们首先要知道,默认情况下,spring在实例化容器中的对象时是按名称进行自然排序进行实例化的。比如我们现在有A,B,C三个对象,那么spring在实例化时会按照A,B,C这样的顺序进行实例化。

    但是,在某些情况下我们可能需要B在A之前完成实例化。这个时候,我们就需要使用depends-on这个属性了。

  -- lazy:

    默认情况下,spring会在容器启动阶段完成所有bean的实例化,以及一系列的生命周期回调。

    但是,某些情况下我们可能需要让某一个bean延迟实例化。这种情况下,我们需要用到lazy属性。

4. BeanDefinition

  BD包含了我们对 bean 做的配置,,比如  XML </bean> 标签的形式进行的配置。

  BD是 spring 对 bean 抽象 后的实体。 它是 spring 创建 bean 的一个标准。

  BD 包含以下与数据:

    -- 一个全限定 类名, 通常来说, 就是对应的 bean 的 全限定类名。

    -- bean 的 行为 配置 元素,  这些  元素 展示了  这个 bean 在容器中 是 如何 工作的, 包括 scope, lifecycle, callbacks 等等。

    -- 这个bean的 依赖信息。

    -- 一些其他配置信息, 比如 我们 配置了一个连接池对象, 那么我们还会配置 其他的池子 大小, 最大连接数等。

  4.1 普通创建bean vs  BD创建bean

    普通: 磁盘上的两个.class文件 , 通过 ClassLoader 加载 成了 JVM 方法区中的两个 class 对象, 然后 通过 new 的方式 创建了 两个对象(ok);

    BD:  磁盘上的两个.class 文件, 通过 ClassLoader 加载 成了 JVM 方法区中的两个 class 对象,而 spring 对其管理得 bean 没有直接采用 new 的方式。 而是 先 通过 解析 配置数据 以及 根据对象 本身的一些定义 而 获取 其 对应的 beanDefinition, 并将这个beanDefinition 作为 之后 创建 这个 bean 的 依据。同时 spring 在这个过程中 提供了 一些 扩展点, 例如 我们在图中所 提到了 BeanFactoryProcessor.  (ok)

  4.2 总结:

    什么是BeanDefinition? 总结起来就是一句话,Spring 创建 bean 是 的 建模对象。

    BeanDefinition 具体使用的子类,以及 Spring 在 哪些地方使用到了 他们。 )(不懂)

  4.3 内容补充:

    单例:

      一个单例的bean 意味着, 这个bean 只会 容器 创建 一次。 在 创建后, 容器中的 每个地方 使用的 都是 同一个 bean 对象。

      <bean scope='singleton' />

      @Component // 这里配置singleton,默认就是singleton @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public class LuBanService{ }

    原型:

      一个原型的bean 意味着, 每次我们使用时, 都会重新 创建 这个 bean。

      <bean scope='ptototype' />

      @Component // 这里配置prototype @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class LuBanService{ }

5. BeanDefinition

  5.1 什么是 合并?

    一个BD 包含了 很多 配置信息。包括构造函数的参数,  setter方法 的参数, 还有 容器一些特定的配置信息。 比如 初始方法, 静态方法等等。

    一个 子 BD 可以继承 父 BD的 配置信息, 不仅如此,还可以覆盖 其中的 一些值,或者 添加一些自己需要的属性。

    一个父 BD 可以作为 BD 定义的模板。

      简单的总结就是: 子 BD 会从 父 BD 继承没有的属性。子 BD 已经存在的属性不会被覆盖。

      关于 父 BD 中 abstract 属性的 说明: 并不是作为 父 BD 就一定要有 abstract 属性,abstract 只是 代表了 这个 BD 是否要被 Spring 进行 实例化,并 创建 对应的 bean, 如果为 true,代表容器不需要对其进行实例化。

                       如果一个 父 BD 没有 class 属性, 那么 必须要设置 其 abstract 为 true;

                       一般 作为 父 BD 都设置 abstract 为 true,因为我们只是要继承这个模板,而不是 实例化父 BD。 要是设置abstract 为 true, 你又不去继承他,他自己又不能实例化,那没啥用了,这个。

  5.2 Spring 在 哪些阶段做了 合并?

    -- Spring 扫描 获取 BD 时。

    -- Spring 在 实例化一个 BD 时 也会进行 合并。

         在扫描阶段之所以要合并,是因为 String 需要 拿到 指定了、实现了 BeanDefinitionRegistryPostProcessor 接口的 BD 的 名称。

          在实例化阶段, Spring 需要用到 BD 中的 一些列属性 做 判断, 所以进行了一系列合并,。

            总结起来就是一个原因: Spring 需要用到 BD 的属性, 要保证获取到的BD 的属性是正确的。

总结: BeanDefinition 这个类很重要, 是整个Spring 的基石。  之所以每次用到 BD 都要进行一次合并,是为了每次拿到都是 最新的,最有效的。 因为利用容器提供 的 一些扩展点 我们可以修改 BD 中的一些属性。

6. BeanDefinitionRegistryPostProcessor 的 作用。

    -- BeanFactoryPostProcessor 可以对 Bean 配置元数据 进行 操作。 也就是说, Spring 允许 BFPP 读取指定 bean 的 配置 元数据, 并可以在 bean 被实例化之前  修改它。

      这里说的 配置元数据 其实就是 我们之前所说的 BeanDefinition。

    -- 我们可以配置 多个 BFPP, 并且 只要 我们 配置的 BFPP 同时实现了 Ordered 接口的话,我么 还可以控制这些  BFPP 的 执行顺序。

  6.1. 

    -- Ordered 接口  用于 决定 执行顺序。

    --  PriorityOrdered  这个接口 直接 继承了 Ordered 接口,并没有做 任何 扩展。 只是作为 一个 标记 接口, 也 用于 决定 BFPP 的执行顺序。

    --  Aware  先不管。

    --  FunctionalInterface ,这是 Java 8 新增 的一个接口,也是只起标记作用,标记该接口是一个函数式接口。

    --  BeanFactoryPostProcessor 代表这个类是一个 Bean 工厂的后置处理器。

    --  PropertiesLoaderSupport, 这个类主要 包含 定义了 属性的 加载方法。包含属性如下:

          @Nullable

            Protected Properties []  localProperties;     // 本地属性,可以直接在XML 中配置。

          

          Protected boolean localOverirde = false;              //  是否本地的属性覆盖提供的文件中的属性, 默认不会。

          @NUllable

            Privated Resource []   locations;                   // 根据地址找到对应的文件。

            privated boolean  ignoreResourceNotFound = false;                                             //   没有找到文件是否抛出异常; false  不抛出;

          @Nullable

            private String fileEncoding;                         //  对应文件资源的编码

          private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();           //  文件解析器

    -- PropertyResourceConfigurer ,  这个类可以对读取到的一些 属性 进行 转换;

    --  PlaceholderConfigurerSupport   ,  主要负责对占位符进行 解析。其中的几个属性如下:

          public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";           //  默认解析的前缀

          public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";    //  默认解析的后缀

          public static final String DEFAULT_VALUE_SEPARATOR = ":";      // 属性名 跟 属性值 的分隔符

    -- PropertyPlaceholderConfigurer  继承了上面这些类的所有功能, 同时 可以配置属性的解析顺序。如:

          public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0;    // 不在系统属性中查找

          public static final int SYSTEM_PROPERTIES_MODE_FALLBACK = 1;   // 如果没有在配置文件中找到,再去系统属性中查找

          public static final int SYSTEM_PROPERTIES_MODE_OVERRIDE = 2;   //  先查找系统中的属性,没有再去查找配置文件中的属性

总结: BFPP 执行的顺序总结如下:

    -- 先执行直接实现了 BeanFactoryRegestryPostProcessor 接口的后置 处理器, 所有实现了BeanDefinitionRegistryPostProcessor 接口的类有 两个 方法: 一个是 PostProcessBeanDefinitionRegistry 方法, 一个是继承父接口的 PostProcessBeanFactory 方法。

    -- PostProcessBeanDefinitoinRegistry 方法 早于 PostProcessBeanFactory 方法执行, 对于 PostProcessBeanDefinitionRegistry 的执行顺序 又 遵循 如下 原子:

      先执行 实现了 PriorityOrdered 接口的类中 的 PostProcessBeanDefinitionRegistry 方法;   再执行实现了 Ordered 接口的 类中 的 PostProcessBeanDefinitionRegistry 的 方法;    最后执行没有实现上面两个接口 的 类 中 的  PostProcessBeanDefinitionRegistry 方法;

    -- 执行 完成 所有 的 PostProcessBeanDefinitionRegistry 方法后, 再执行 实现了 BeanFactoryPostProcessor 接口的后置处理器:

      先执行实现了 PriorityOrdered 接口的类中的 PostProcessBeanFactory 方法;   再执行实现了 Ordered 接口中 的 PostProcessBeanFactory 方法;  最后 执行没有实现上面两个接口类中 PostProcessBeanFactory 的 方法。

         

7. FactoryBean:      (Spring 中的  一个 特殊的 bean,  Spring 利用它 提供 了 一个 创建 bean 的方式)

  -- FactoryBean  主要用来 定制化 Bean 的 创建 逻辑

  -- 当我们实例化一个Bean 的逻辑很复杂的 时候, 使用 FactoryBean 是很必要的, 这样 可以 规避我们 去使用 过长 的 XML 配置。

  -- FactoryBean 提供了以下 三个方法:

    Object getObject()   //  返回这个 FactoryBean 所创建的 对象。

    boolean  isSingleton()   // 返回 FactoryBean 所创建的对象是否为 单例。默认返回true;

    Class  GetObjectType()   // 返回这个 FactoryBean 所创建的 对象的 类型, 如果我们能确认返回的对象的 类型的 话,我们应该正常 对这个方法 做出实现,而不是 返回 null。

  7.1 Spring 自身大量使用了 FactoryBean 这个概念。至少有 50 个 BeanFactory 实现类 存在 于 Spring 容器中。  、、、;

    ;假设我们定义了一个 FactoryBaen,名为 MyfactoryBean, 当我们调用 getBean('MyFactoryBean‘’)  方法时,返回的并不是这个FactoryBean, 而是这个 FactoryBean 所创建的 Bean, 如果我们想要获取到 这个 FactoryBean, 需要在 名字前面 拼接 ‘&‘’’ 如:‘getBean("myFactoryBean")’;

  7.2 SmartFactoryBean (  继承了 FactoryBean  的 唯一子接口,并且默认这个接口的实例是 懒加载的,就是 Spring 在启动时, 不会立即将这个 bean 创建出来)

    为了让这个 bean 在 spring 启动的时候就创建 出来, 我们在实现 SmartFactoryBean 时, 需要重写 isEagerInit 方法,将返回值 设为 true;

                            我们也可以在 一个不是懒加载的 Bean 中 注入  这个 SmartFactoryBean 所创建的 bean, Spring 为了解决依赖关系,也会将这个 bean 创建 出来。

  7.3 BeanDefinition   vs     FactoryBean

    @Configuration public class Config { @Bean public B b(){ return new B(); } }

     我们通过 @Bean 的方式 来  创建一个Bean,  那么 在 B  的 BeanDefinition 会 记录  factoryBeanName 这个属性, 同时 还会记录 是 这个 Bean 中 哪个 方法 创建 B 的。如: factoryBeanName = config,   factoryMethodName = b;

  7.4  FactoryBean 相关的面试题:

    FactoryBean  和  BeanFactory  的 区别:     FB 是 Spring 提供的 一个 扩展点,适用于 复杂 的 bean 的 创建。 Mybatis 在 和 Spring 整合 时 就用 到了这个扩展点。 并且 FB 创建的 Bean 和 普通的 Bean 不一样。FB 是Spring 创建Bean 的另一种手段。

java spring 理解的更多相关文章

  1. 从零开始学 Java - Spring 集成 ActiveMQ 配置(一)

    你家小区下面有没有快递柜 近两年来,我们收取快递的方式好像变了,变得我们其实并不需要见到快递小哥也能拿到自己的快递了.对,我说的就是类似快递柜.菜鸟驿站这类的代收点的出现,把我们原来快递小哥必须拿着快 ...

  2. 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)

    硬盘和内存的作用是什么 硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片.视频.各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里 ...

  3. 从零开始学 Java - Spring AOP 实现主从读写分离

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  4. Java Spring IOC用法

    Java Spring IOC用法 Spring IoC 在前两篇文章中,我们讲了java web环境搭建 和 java web项目搭建,现在看下spring ioc在java中的运用,开发工具为In ...

  5. Effective Java通俗理解(下)

    Effective Java通俗理解(上) 第31条:用实例域代替序数 枚举类型有一个ordinal方法,它范围该常量的序数从0开始,不建议使用这个方法,因为这不能很好地对枚举进行维护,正确应该是利用 ...

  6. Java Spring Boot VS .NetCore (一)来一个简单的 Hello World

    系列文章 Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filte ...

  7. Java Spring Boot VS .NetCore (二)实现一个过滤器Filter

    Java Spring Boot VS .NetCore (一)来一个简单的 Hello World Java Spring Boot VS .NetCore (二)实现一个过滤器Filter Jav ...

  8. 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)

    Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...

  9. [java] 深入理解内部类: inner-classes

    [java] 深入理解内部类: inner-classes // */ // ]]>   [java] 深入理解内部类: inner-classes Table of Contents 1 简介 ...

  10. 从零开始学 Java - Spring 集成 ActiveMQ 配置(二)

    从上一篇开始说起 上一篇从零开始学 Java - Spring 集成 ActiveMQ 配置(一)文章中讲了我关于消息队列的思考过程,现在这一篇会讲到 ActivMQ 与 Spring 框架的整合配置 ...

随机推荐

  1. day04-视图和视图解析器

    视图和视图解析器 1.基本介绍 在SpringMVC中的目标方法,最终返回的都是一个视图(有各种视图) 注意,这里的视图是一个类对象,不是一个页面!! 返回的视图都会由一个视图解析器来处理(视图解析器 ...

  2. Android第六次作业

    图片一 用内部存储实现文件写入和读取功能 <?xml version="1.0" encoding="utf-8"?> <LinearLayo ...

  3. HEU_KMS_Activator_v27.0.2全能系统数字许可激活工具

    HEU_KMS_Activator_v27.0.2全能系统数字许可激活工具 HEU KMS Activator是KMS激活工具,支持激活 Windows XP.Windows 7.Windows 8. ...

  4. 解决 Vue3 中路由切换到其他页面再切换回来时 Echarts 图表不显示的问题

    问题复现: 正常状态下: 切换到其他页面再切换回来: 问题解决: 其实这个问题的解决方式官网写得清清楚楚,我们看看官网怎么解决的: 接下来我用代码解释下这句话(正确的做法是,在图表容器被销毁之后,调用 ...

  5. STM32F0_HAL初始化系列:串口DMA输出

    static void MX_USART1_UART_Init(void) { /* USER CODE BEGIN USART1_Init 0 */ /* USER CODE END USART1_ ...

  6. 华为eNSP 基础企业级WLAN配置

    目标:STA可以扫描并连接到两个ssid,STA可以ping通ip:200.200.200.200 步骤:1 实现AP与AC之间的连通性.     2 在AC上配置与WLAN相关的各项参数 3 把AP ...

  7. C#:开发一个winform窗体程序,实现强势股票池的数据获取。(需对接第三方接口,目前可免费使用)

    写在前面:短暂的接触过一段时间的股票市场,只能说A股真的太能杀了! 开发这个工具的初衷呢,是和几个好友在每日做"慈善"后,突发奇想:如果能实时获取当前股市里强势的股票就好了,因为这 ...

  8. sqllabs靶场less1-4

    less1-4 语法:Select 列名称 from 表名称 (where column_name='xxx' and -) 在数据库中: information_schema:存放和数据库有关的东西 ...

  9. PostgreSQL 打印详细错误调用栈 - pg_backtrace

    一.用法 create extension pg_backtrace; select pg_backtrace_init(); 二.示例 postgres=# select count(*)/0.0 ...

  10. js提示框触发和定时关闭

    <!DOCTYPE html><meta charset="utf-8"> <script src="https://cdn.staticf ...