• Spring进阶(五):其他


    一、FactoryBean

    代码参考a43包

    收获

    1. 它的作用是用制造创建过程较为复杂的产品, 如 SqlSessionFactory, 但 @Bean 已具备等价功能
    2. 使用上较为古怪, 一不留神就会用错
      1. 被 FactoryBean 创建的产品
        • 会认为创建、依赖注入、Aware 接口回调、前初始化这些都是 FactoryBean 的职责, 这些流程都不会走
        • 唯有后初始化的流程会走, 也就是产品可以被代理增强
        • 单例的产品不会存储于 BeanFactory 的 singletonObjects 成员中, 而是另一个 factoryBeanObjectCache 成员中
      2. 按名字去获取时, 拿到的是产品对象, 名字前面加 & 获取的是工厂对象

    二、 @Indexed 原理

    真实项目中,只需要加入以下依赖即可

    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-context-indexerartifactId>
        <optional>trueoptional>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    代码参考a44包

    收获

    1. 在编译时就根据 @Indexed 生成 META-INF/spring.components 文件
    2. 扫描时
      • 如果发现 META-INF/spring.components 存在, 以它为准加载 bean definition
      • 否则, 会遍历包下所有 class 资源 (包括 jar 内的)
    3. 解决的问题,在编译期就找到 @Component 组件,节省运行期间扫描 @Component 的时间

    三、代理进一步理解

    代码参考a45包

    收获

    1. spring 代理的设计特点
      • 依赖注入和初始化影响的是原始对象
        • 因此 cglib 不能用 MethodProxy.invokeSuper()
      • 代理与目标是两个对象,二者成员变量并不共用数据
    2. static 方法、final 方法、private 方法均无法增强
      • 进一步理解代理增强基于方法重写

    四、@Value 装配底层

    按类型装配的步骤

    1. 查看需要的类型是否为 Optional,是,则进行封装(非延迟),否则向下走
    2. 查看需要的类型是否为 ObjectFactory 或 ObjectProvider,是,则进行封装(延迟),否则向下走
    3. 查看需要的类型(成员或参数)上是否用 @Lazy 修饰,是,则返回代理,否则向下走
    4. 解析 @Value 的值
      1. 如果需要的值是字符串,先解析 ${ },再解析 #{ }
      2. 不是字符串,需要用 TypeConverter 转换
    5. 看需要的类型是否为 Stream、Array、Collection、Map,是,则按集合处理,否则向下走
    6. 在 BeanFactory 的 resolvableDependencies 中找有没有类型合适的对象注入,没有向下走
    7. 在 BeanFactory 及父工厂中找类型匹配的 bean 进行筛选,筛选时会考虑 @Qualifier 及泛型
    8. 结果个数为 0 抛出 NoSuchBeanDefinitionException 异常
    9. 如果结果 > 1,再根据 @Primary 进行筛选
    10. 如果结果仍 > 1,再根据成员名或变量名进行筛选
    11. 结果仍 > 1,抛出 NoUniqueBeanDefinitionException 异常

    @Value 装配过程 代码参考 a46包

    收获

    1. ContextAnnotationAutowireCandidateResolver 作用之一,获取 @Value 的值
    2. 了解 ${ } 对应的解析器
    3. 了解 #{ } 对应的解析器
    4. TypeConvert 的一项体现

    五、@Autowired 装配底层

    @Autowired 装配过程 代码参考 a47包

    收获

    1. @Autowired 本质上是根据成员变量或方法参数的类型进行装配
    2. 如果待装配类型是 Optional,需要根据 Optional 泛型找到 bean,再封装为 Optional 对象装配
    3. 如果待装配的类型是 ObjectFactory,需要根据 ObjectFactory 泛型创建 ObjectFactory 对象装配
      • 此方法可以延迟 bean 的获取
    4. 如果待装配的成员变量或方法参数上用 @Lazy 标注,会创建代理对象装配
      • 此方法可以延迟真实 bean 的获取
      • 被装配的代理不作为 bean
    5. 如果待装配类型是数组,需要获取数组元素类型,根据此类型找到多个 bean 进行装配
    6. 如果待装配类型是 Collection 或其子接口,需要获取 Collection 泛型,根据此类型找到多个 bean
    7. 如果待装配类型是 ApplicationContext 等特殊类型
      • 会在 BeanFactory 的 resolvableDependencies 成员按类型查找装配
      • resolvableDependencies 是 map 集合,key 是特殊类型,value 是其对应对象
      • 不能直接根据 key 进行查找,而是用 isAssignableFrom 逐一尝试右边类型是否可以被赋值给左边的 key 类型
    8. 如果待装配类型有泛型参数
      • 需要利用 ContextAnnotationAutowireCandidateResolver 按泛型参数类型筛选
    9. 如果待装配类型有 @Qualifier
      • 需要利用 ContextAnnotationAutowireCandidateResolver 按注解提供的 bean 名称筛选
    10. 有 @Primary 标注的 @Component 或 @Bean 的处理
    11. 与成员变量名或方法参数名同名 bean 的处理

    六、事件监听器

    事件监听器 代码参考 a48包

    收获

    事件监听器的两种方式

    1. 实现 ApplicationListener 接口
      • 根据接口泛型确定事件类型
    2. @EventListener 标注监听方法
      • 根据监听器方法参数确定事件类型
      • 解析时机:在 SmartInitializingSingleton(所有单例初始化完成后),解析每个单例 bean

    七、事件发布器

    事件发布器 代码参考 a49包

    收获

    事件发布器模拟实现

    1. addApplicationListenerBean 负责收集容器中的监听器
      • 监听器会统一转换为 GenericApplicationListener 对象,以支持判断事件类型
    2. multicastEvent 遍历监听器集合,发布事件
      • 发布前先通过 GenericApplicationListener.supportsEventType 判断支持该事件类型才发事件
      • 可以利用线程池进行异步发事件优化
    3. 如果发送的事件对象不是 ApplicationEvent 类型,Spring 会把它包装为 PayloadApplicationEvent 并用泛型技术解析事件对象的原始类型
      • 视频中未讲解
  • 相关阅读:
    学内核之十一:ARM64屏障指令使用指南
    SHAP - 解释机器学习
    深度学习中的熵、交叉熵、相对熵(KL散度)、极大释然估计之间的联系与区别
    python绑定游戏窗口模拟键盘鼠标操作方法64位32位通用
    WSL安装异常:WslRegisterDistribution failed with error: 0xc03a001a
    【软考 系统架构设计师】项目管理① 立项管理
    【安全狗高危安全通告】GitLab远程代码执行漏洞
    【前端验证】通关寄存器与ral_model —— 生成的RTL代码分析(1)
    当BIM遇上VR。让你体会一把什么是win win~
    2.4_2死锁的处理策略---预防死锁
  • 原文地址:https://blog.csdn.net/qq_38697437/article/details/126101003