网站建设客源,ppt模板免费下载图片,女生学建筑工程技术就业前景,网络营销计划包括哪七个步骤前言
源码在我github的guide-spring仓库中#xff0c;可以克隆下来 直接执行。
我们本文主要来介绍依赖查找的使用示例
依赖查找
什么是依赖查找
依赖查找并不是 Spring 框架特有的概念#xff0c;它是一种在软件开发中获取依赖对象的方式。它通常用于获取运行时需要的服…前言
源码在我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环境中你可以使用JNDIJava 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, ClassT requiredType) throws BeansException;T T getBean(ClassT requiredType) throws BeansException;T ObjectProviderT getBeanProvider(ClassT requiredType);T ObjectProviderT getBeanProvider(ResolvableType requiredType);}可以看出上述定义我们可以通过 Bean 名称、Bean 名称 类型、类型等方式进行依赖查找 Bean。下面我们分别从单一类型、集合类型、层次类型、延迟等方式依次展示依赖查找的示例。
单一类型的依赖查找
单一类型的查找需要要求容器中同一类型的Bean只能有一个为 primary BeanDefinition中的概念我们可以看下 xml 配置示例
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdbean iduser classcom.markus.spring.ioc.overview.domain.Userproperty nameid value1/property nameusername valuemarkus zhang//bean!-- 当有多个 User 时需要指出 其中一个 Bean 的 primary属性为 true 否则会出现 NoUniqueBeanDefinitionException --bean iduser2 classcom.markus.spring.ioc.overview.domain.User lazy-inittrue primarytrueproperty nameid value2/property nameusername valuemarkus 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 并且 返回一个 MapString,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;MapString, 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* Its my honor to share what Ive 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 的示例 即 HierarchicalBeanFactorySystem.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 version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdbean iduser2 classcom.markus.spring.ioc.overview.domain.User lazy-inittrue primarytrueproperty nameid value2/property nameusername valuemarkus zhang//beanbean idfactoryBean classorg.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBeanproperty nametargetBeanName valueuser2//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)ObjectFactoryUser factoryBean (ObjectFactoryUser) beanFactory.getBean(factoryBean);System.out.println(延迟生效中....);System.out.println(延迟查找: factoryBean.getObject());}}Spring内建可查找的依赖
除了我们自己配置的Bean我们还可以查找 Spring 框架内 注册的单例 Bean。具体如下
environment Environment 外部化配置以及ProfilessystemProperties Properties Java系统属性systemEnvironment MapString,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* Its my honor to share what Ive 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#prepareBeanFactoryorg.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors(org.springframework.beans.factory.support.BeanDefinitionRegistry, java.lang.Object)
依赖查找的常见异常
下面这些就是场景的在使用依赖查找的时候可能会触发的异常都是 BeansException 的子类型。场景比较清晰这里就不写具体的示例了。
异常类型触发条件场景举例NoSuchBeanDefinitionException当查找 Bean 不存在于 IoC 容器 时BeanFactory#getBeanNoUniqueBeanDefinitionException类型依赖查找时IoC 容器存在多 个 Bean 实例BeanFactory#getBean(Class)BeanInstantiationException当 Bean 所对应的类型非具体类时BeanFactory#getBeanBeanCreationException当 Bean 初始化过程中Bean 初始化方法执行异常时BeanDefinitionStoreException当 BeanDefinition 配置元信息非 法时XML 配置资源无法打开时
本文总结
好了到这就基本上把 Spring 依赖查找相关的知识点就总结完了本文我们主要总结了依赖查找的几种方式包括单一类型、集合类型、层次性、延迟性以及 Spring 内建 Bean 的依赖查找并给出了 Spring 内建 Bean 注册的源码位置最后提到了依赖查找的几个常见的异常并给出了常见场景触发的条件。
关于 Spring 依赖 还有依赖注入、依赖来源等知识 后面会跟进梳理。
以上也是我在学习 Spring 时参考的资料并加上了自己的理解如有错误欢迎交流。