Spring 依赖查找知识点总结

前言

源码在我github的guide-spring仓库中,可以克隆下来 直接执行。

我们本文主要来介绍依赖查找的使用示例

依赖查找

什么是依赖查找

依赖查找并不是 Spring 框架特有的概念,它是一种在软件开发中获取依赖对象的方式。它通常用于获取运行时需要的服务、组件或其他对象的引用。在面向对象编程中,依赖通常体现为一个对象需要另一个对象的服务或功能。

在不同的编程框架和容器中,依赖查找的方式可能会有所不同。我们简单罗列一些常见的依赖查找的例子:

Java中的依赖查找

  • 在纯 Java 环境中,依赖查找通常通过构造函数、方法参数或其他手段来获得依赖对象的引用。
  • 例如,通过在一个对象的构造函数中传递另一个对象的引用:
public class MyClass {private DependencyClass dependency;public MyClass(DependencyClass dependency) {this.dependency = dependency;}// ...
}

Spring框架中的依赖查找

  • 在Spring框架中,依赖查找通常通过 Spring 容器来实现。你可以使用ApplicationContextor BeanFactory 来获取所需的 Bean 。

    public class UseDependencyLookupDemo {public static void main(String[] args) throws Exception {BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup.xml");// 1. 实时查找realtimeLookup(beanFactory);}private static void realtimeLookup(BeanFactory beanFactory) {// 名称+类型User user = beanFactory.getBean("user", User.class);System.out.println("实时查找: " + user);}
    }
    
  • 或者,通过在类中使用@Autowired注解来自动注入依赖:

    @Service
    public class MyService {@Autowiredprivate DependencyClass dependency;// ...
    }
    

Java EE中的依赖查找:

  • 在Java EE环境中,你可以使用JNDI(Java Naming and Directory Interface)进行依赖查找。通过JNDI,你可以在运行时查找和获取命名对象。

    public class JNDIDependencyLookupDemo {public static void main(String[] args) throws NamingException {// 设置JNDI环境属性Properties properties = new Properties();properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");properties.put(Context.PROVIDER_URL, "file:/META-INF/jndi");// 初始化InitialContextContext initialContext = new InitialContext(properties);// 在文件系统上查找一个名为 "user" 的对象User user = (User) initialContext.lookup("user");System.out.println("JNDI Lookup Result: " + user);}
    }
    

依赖查找的方式

依赖查找的方式有很多,我们先看下 BeanFactory 的 接口定义:

public interface BeanFactory {Object getBean(String name) throws BeansException;<T> T getBean(String name, Class<T> requiredType) throws BeansException;<T> T getBean(Class<T> requiredType) throws BeansException;<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);}

可以看出上述定义,我们可以通过 Bean 名称、Bean 名称 + 类型、类型等方式进行依赖查找 Bean。下面我们分别从单一类型、集合类型、层次类型、延迟等方式依次展示依赖查找的示例。

单一类型的依赖查找

单一类型的查找,需要要求容器中同一类型的Bean只能有一个为 primary (BeanDefinition中的概念),我们可以看下 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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.markus.spring.ioc.overview.domain.User"><property name="id" value="1"/><property name="username" value="markus zhang"/></bean><!-- 当有多个 User 时,需要指出 其中一个 Bean 的 primary属性为 true 否则会出现 NoUniqueBeanDefinitionException --><bean id="user2" class="com.markus.spring.ioc.overview.domain.User" lazy-init="true" primary="true"><property name="id" value="2"/><property name="username" value="markus zhang"/></bean></beans>

我们来看下使用示例

public class UseDependencyLookupDemo {public static void main(String[] args) throws Exception {BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup.xml");typeLookup(beanFactory);}/*** ========================按照 Bean 类型查找========================*//*** 单个Bean类型查找** @param beanFactory*/private static void typeLookup(BeanFactory beanFactory) {User user = beanFactory.getBean(User.class);System.out.println(user);}
}
集合类型的依赖查找

与单一类型查找的区别在于,它不需要指定 primary 并且 返回一个 Map<String,T> 对象,key 为 Bean 的名称,value 为 Bean 实例。

public class UseDependencyLookupDemo {public static void main(String[] args) throws Exception {BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup.xml");// 4. 按照类型查找多个BeancollectionLookup(beanFactory);}/*** 根据集合类型查找*/private static void collectionLookup(BeanFactory beanFactory) {if (beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;Map<String, User> userMap = listableBeanFactory.getBeansOfType(User.class);userMap.forEach((beanName, user) -> System.out.println("Bean name: " + beanName + ", User: " + user));}}
}
层次类型的依赖查找

层次性依赖查找,体现在父子容器中,我们一般可能体会不到,实际上 Spring MVC 的底层就涉及父子容器的概念,即 Root ApplicationContext 和 Dispatcher-Servlet ApplicationContext。这里不展开了。我们通过一个简单的示例来展示层次性依赖查找 Bean

package com.markus.spring.dependency.lookup;import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** @author: markus* @date: 2023/12/17 10:23 PM* @Description: {@link HierarchicalBeanFactory}* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class HierarchicalBeanFactoryDependencyDemo {public static void main(String[] args) {ConfigurableListableBeanFactory subBeanFactory = new DefaultListableBeanFactory();// 设置父容器subBeanFactory.setParentBeanFactory(createParent());// 展示 仅在当前 Bean 容器中是否 存在System.out.println(displayContainBean(subBeanFactory, "user", true));// 展示 父子 Bean 容器中是否 存在(体现出 可继承 BeanFactory 的示例 即 HierarchicalBeanFactory)System.out.println(displayContainBean(subBeanFactory, "user", false));}private static boolean displayContainBean(ConfigurableListableBeanFactory beanFactory, String beanName, boolean onlyLocal) {boolean result = beanFactory.containsLocalBean(beanName);if (!onlyLocal) {if (!result) {BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();if (parentBeanFactory != null) {result = parentBeanFactory.containsBean(beanName);}}}return result;}private static ConfigurableListableBeanFactory createParent() {ConfigurableListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();BeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) parentBeanFactory);String location = "classpath:/META-INF/dependency-lookup.xml";// 加载 父容器 的 Bean 实例beanDefinitionReader.loadBeanDefinitions(location);return parentBeanFactory;}
}
延迟依赖查找

延迟依赖查找通常体现在懒加载 Bean 的场景,比如一些大资源的Bean希望在使用到的时候才会触发初始化以达到降低服务启动时间的目的,这个时候就可以使用懒加载模式,而在我们依赖查找的时候,使用延迟依赖查找的时候,也不会触发 Bean 的初始化,只有在真正使用到对象的时候才会触发初始化。(ps 比较绕,我们直接看例子)

因为 Bean 元信息配置比较特殊,我把 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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user2" class="com.markus.spring.ioc.overview.domain.User" lazy-init="true" primary="true"><property name="id" value="2"/><property name="username" value="markus zhang"/></bean><bean id="factoryBean" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean"><property name="targetBeanName" value="user2"/></bean></beans>

使用示例

public class UseDependencyLookupDemo {public static void main(String[] args) throws Exception {BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup.xml");lazyLookup(beanFactory);}/*** 延迟查找*/private static void lazyLookup(BeanFactory beanFactory) throws Exception {@SuppressWarnings("unchecked")ObjectFactory<User> factoryBean = (ObjectFactory<User>) beanFactory.getBean("factoryBean");System.out.println("延迟生效中....");System.out.println("延迟查找: " + factoryBean.getObject());}}

Spring内建可查找的依赖

除了我们自己配置的Bean,我们还可以查找 Spring 框架内 注册的单例 Bean。具体如下:

  • environment Environment 外部化配置以及Profiles
  • systemProperties Properties Java系统属性
  • systemEnvironment Map<String,String> 操作系统环境变量
  • messageSource MessageSource 国家化文案
  • lifecycleProcessor LifecycleProcessor Lifecycle Bean 处理器
  • applicationEventMulticaster ApplicationEventMulticaster Spring 事件广播器
  • internalConfigurationAnnotationProcessor ConfigurationClassPostProcessor 处理 Spring 的配置类
  • internalAutowiredAnnotationProcessor AutowiredAnnotationBeanPostProcessor 处理 @Autowired 以及 @Value、@Inject注解
  • internalCommonAnnotationProcessor CommonAnnotationBeanPostProcessor 处理 JSR-250 注解,如 @Resource、@PostConstruct等
  • internalEventListenerProcessor EventListenerMethodProcessor 处理标注 @EventListener 的 Spring 事件监听方法
  • internalEventListenerFactory DefaultEventListenerFactory 处理@EventListener 事件监听方法适配为 ApplicationListener

我们来看下示例:

package com.markus.spring.dependency.lookup;import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.LifecycleProcessor;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.DefaultEventListenerFactory;
import org.springframework.context.event.EventListenerMethodProcessor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.Environment;import java.util.Properties;/*** @author: markus* @date: 2023/12/17 10:54 PM* @Description: Spring 内建依赖的 依赖查找示例* @Blog: https://markuszhang.com* It's my honor to share what I've learned with you!*/
public class SpringInternalBeanDependencyLookDemo {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup.xml");displaySpringInternalBean(context, Environment.class);displaySpringInternalBean(context, Properties.class);displaySpringInternalBeanByName(context, "systemEnvironment");displaySpringInternalBean(context, MessageSource.class);displaySpringInternalBean(context, LifecycleProcessor.class);displaySpringInternalBean(context, ApplicationEventMulticaster.class);// 关闭 Spring 容器上下文context.close();// 基于 注解驱动 的应用上下文AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();annotationConfigApplicationContext.register(SpringInternalBeanDependencyLookDemo.class);annotationConfigApplicationContext.refresh();displaySpringInternalBean(annotationConfigApplicationContext, ConfigurationClassPostProcessor.class);displaySpringInternalBean(annotationConfigApplicationContext, AutowiredAnnotationBeanPostProcessor.class);displaySpringInternalBean(annotationConfigApplicationContext, CommonAnnotationBeanPostProcessor.class);displaySpringInternalBean(annotationConfigApplicationContext, EventListenerMethodProcessor.class);displaySpringInternalBean(annotationConfigApplicationContext, DefaultEventListenerFactory.class);annotationConfigApplicationContext.close();}private static void displaySpringInternalBean(ApplicationContext context, Class<?> type) {Object bean = context.getBean(type);System.out.println(bean);}private static void displaySpringInternalBeanByName(ApplicationContext context, String beanName) {Object bean = context.getBean(beanName);System.out.println(bean);}
}

可以看到上面我们引入了基于 Xml 驱动的Spring应用上下文以及基于 注解 驱动的Spring应用上下文来实现 Spring 内建 Bean 的依赖查找。

ps: 如果一个默认的 ClassPathXmlAppplicationContext 不会包含ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等这些注解的依赖,需要我们在 xml 配置文件中开启 注解启动,才会注册进 Spring IoC容器中。

大家可能会有疑问,这些 Spring 内建的 Bean 是什么时候被注册进去呢?这里给下源码位置,感兴趣的可以自行查看:

  • org.springframework.context.support.AbstractApplicationContext#prepareBeanFactory
  • org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)

依赖查找的常见异常

下面这些就是场景的在使用依赖查找的时候可能会触发的异常,都是 BeansException 的子类型。场景比较清晰,这里就不写具体的示例了。

异常类型触发条件场景举例
NoSuchBeanDefinitionException当查找 Bean 不存在于 IoC 容器 时BeanFactory#getBean
NoUniqueBeanDefinitionException类型依赖查找时,IoC 容器存在多 个 Bean 实例BeanFactory#getBean(Class)
BeanInstantiationException当 Bean 所对应的类型非具体类时BeanFactory#getBean
BeanCreationException当 Bean 初始化过程中Bean 初始化方法执行异常时
BeanDefinitionStoreException当 BeanDefinition 配置元信息非 法时XML 配置资源无法打开时

本文总结

好了,到这就基本上把 Spring 依赖查找相关的知识点就总结完了,本文我们主要总结了依赖查找的几种方式,包括单一类型、集合类型、层次性、延迟性以及 Spring 内建 Bean 的依赖查找,并给出了 Spring 内建 Bean 注册的源码位置,最后提到了依赖查找的几个常见的异常,并给出了常见场景触发的条件。

关于 Spring 依赖 还有依赖注入、依赖来源等知识 后面会跟进梳理。

以上也是我在学习 Spring 时参考的资料并加上了自己的理解,如有错误,欢迎交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/229715.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

The Grid – Responsive WordPress Grid响应式网格插件

点击阅读The Grid – Responsive WordPress Grid响应式网格插件原文 The Grid – Responsive WordPress Grid响应式网格插件是一个高级 wordpress 网格插件&#xff0c;它允许您在完全可定制且响应迅速的网格系统中展示任何自定义帖子类型。 Grid WordPress 非常适合展示您的博…

QT信号、槽机制介绍与实现

时间记录&#xff1a;2023/12/17 1.介绍 QT中进行对象之间事件的处理机制为信号、槽机制&#xff0c;即一个对象状态改变时发出信号&#xff0c;然后与此信号进行绑定的对应槽便会被触发&#xff0c;类似于c/c里面的回调函数机制 2.信号 在一定情况下被发射的事件&…

【TB作品】51单片机,语音出租车计价器

西交大题目 1.语音出租车计价器 一、功能要求: 1.具有可模拟出租车车轮转速传感器的硬件设计,可计量出租车所走的公 里数。 2.显示和语音播报里程、价格和等待红灯或堵车的计时价格: 3.具有等待计时功能 4.具有实时年月日显示和切换功能。 5.操作简单、界面友好。 二、设计建议…

08-工厂方法

意图 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类 类图 适用性 在下列情况可以使用工厂方法模式&#xff1a; 当一个类不知道它所必须创建的对象的类的时候。当一个类希望由它的子类来指定它所创建的对象的时候。当类将创建对象的职责委托给多个帮助子…

PCL 已知同名点对计算旋转矩阵并对点云进行旋转

目录 一、 算法概述二、代码实现三、测试示例一、 算法概述 适用:已知三组及三组以上的同名点对,计算旋转矩阵;然后根据旋转矩阵对点云进行旋转,最后保存旋转后的点云文件。 二、代码实现 #include <Eigen/Core> #include <Eigen/Dense>

c++程序设计定义一个MyString类,实现两个字符串连接。要求定义类的数据成员为字符指针,实现深拷贝函数。

定义一个MyString类&#xff0c;实现两个字符串连接。要求定义类的数据成员为字符指针&#xff0c;实现深拷贝函数。 要求&#xff1a;不能使用<string>,可以使用<cstring>中的 strcpy 、strcat、strcmp以及strlen( )等函数 已知测试函数如下&#xff1a; int m…

持久化存储 StorageClass

kubernetes从v1.4版本开始引入了一个新的资源对象StorageClass&#xff0c;用于标记存储资源的特性和性能。到v1.6版本时&#xff0c;StorageClass和动态资源供应的机制得到了完善&#xff0c;实现了存储卷的按需创建&#xff0c;在共享存储的自动化管理进程中能够实现了重要的…

ELK(八)—Metricbeat部署

目录 介绍修改配置文件启动 Modulenginx开启状态查询配置Nginx module查看是否配置成功 介绍 Metricbeat 是一个轻量级的开源度量数据收集器&#xff0c;用于监控系统和服务。它由 Elastic 公司开发&#xff0c;并作为 Elastic Stack&#xff08;Elasticsearch、Logstash、Kiba…

【Linux】在vim中批量注释与批量取消注释

在vim编辑器中&#xff0c;批量注释和取消注释的操作可以通过进入V-BLOCK模式、选择要注释或取消注释的内容、输入注释符号或选中已有的注释符号和按键完成。这些操作可以大大提高代码或文本的编写和修改效率&#xff0c;是vim编辑器中常用的操作之一。 1.在vim中批量注释的步…

[elementPlus] teleported 在 ElSubMenu中的用途

如图 一个菜单对应的路由结构如上图 如果做适配窄屏幕 如果在 <ElSubMenu :index"route.path" >中不加入 teleported 就会出现问题 加上就OK了 <ElSubMenu :index"route.path" teleported>

力扣200. 岛屿数量(java DFS解法)

Problem: 200. 岛屿数量 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 该问题可以归纳为一类遍历二维矩阵的题目&#xff0c;此类中的一部分题目可以利用DFS来解决&#xff0c;具体到本题目&#xff1a; 1.我们首先要针对于二维数组上的每一个点&#xff0c;尝试展…

单片机期末复习

前言 发现很多人都写了单片机原理及接口技术课后习题的答案&#xff0c;但是也就只写了答案而已&#xff0c;可能是他们觉得太简单的缘故吧&#xff0c;我这里对此进行一下我近段时间复习的总结&#xff0c;本篇博客只展示选择题、填空题和判断题的答案&#xff0c;仅供参考&a…

饥荒Mod 开发(十一):修改物品堆叠

饥荒Mod 开发(十)&#xff1a;制作一把AOE武器 饥荒Mod 开发(十二)&#xff1a;一键制作 饥荒中物品栏有限&#xff0c;要拾取的物品有很多&#xff0c;经常装不下要忍痛丢掉各种东西&#xff0c;即使可以将物品放在仓库但是使用不方便&#xff0c;所以可以将物品的堆叠个数设…

1264. 动态求连续区间和(树状数组---某个位置加上一个数/求在线(动态)前缀和/蓝桥杯)

题目&#xff1a; 输入样例&#xff1a; 10 5 1 2 3 4 5 6 7 8 9 10 1 1 5 0 1 3 0 4 8 1 7 5 0 4 8输出样例&#xff1a; 11 30 35 树状数组&#xff1a; 代码&#xff1a; #include<cstdio> #include<iostream> using namespace std;const int N100010; int n,…

系统架构设计师教程(七)系统架构设计基础知识

系统架构设计基础知识 7.1 软件架构概念7.1.1 软件架构的定义7.1.2 软件架构设计与生命周期需求分析阶段设计阶段实现阶段构件组装阶段部署阶段后开发阶段 7.1.3 软件架构的重要性 7.2 基于架构的软件开发方法7.2.1 体系结构的设计方法概述7.2.2 概念与术语7.2.3 基于体系结构的…

Autosar通信实战系列07-Com模块要点及其配置介绍(二)

本文框架 前言1. ComGeneral配置2. ComConfig配置2.1 ComGwMapping2.2 ComIPdus2.3 ComIPduGroups2.4 ComIPduSignals2.5 ComIPduSignalGroups2.6 ComTimeBasis前言 在本系列笔者将结合工作中对通信实战部分的应用经验进一步介绍常用,包括但不限于通信各模块的开发教程,代码…

基于sfunction builder的c-sfunction编写及案例测试分析

目录 前言 1.前期准备工作及文件说明 1.1前期准备工作 1.2 文件说明 1.3 编译方式

深度剖析JavaScript中冒泡和捕获机制、事件代理

JS事件传播的两种机制包括冒泡和捕获&#xff0c;下面将具体剖析它们之间本质的区别。 事件冒泡: 先触发子元素的事件&#xff0c;再触发父元素的事件。 创建一个 ul label 和 li label, 分别绑定一个父id 和 子 id, 再通过创建 script&#xff0c;去绑定各自的点击事件。 <…

阿里云|人工智能(AI)技术解决方案

函数计算部署Stable Diffusion AI绘画技术解决方案 通过函数计算快速部署Stable Diffusion模型为用户提供快速通过文字生成图片的能力。该方案通过函数计算快速搭建了AIGC的能力&#xff0c;无需管理服务器等基础设施&#xff0c;专注模型的能力即可。该方案具有高效免运维、弹…

设计模式——责任链模式(行为模式)

引言 责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链进行发送。 收到请求后&#xff0c; 每个处理者均可对请求进行处理&#xff0c; 或将其传递给链上的下个处理者。 问题 假如你正在开发一个在线订购系统。 你希望对系统访问进行限制&#xff0c; 只允…