当前位置:首页 > 科技  > 软件

如何让 Bean 深度感知 Spring 容器

来源: 责编: 时间:2023-11-03 09:16:52 410观看
导读Spring 有一个特点,就是创建出来的 Bean 对容器是无感的,一个 Bean 是怎么样被容器从一个 Class 整成一个 Bean 的,对于 Bean 本身来说是不知道的,当然也不需要知道,也就是 Bean 对容器的存在是无感的。但是有时候我们可能

Spring 有一个特点,就是创建出来的 Bean 对容器是无感的,一个 Bean 是怎么样被容器从一个 Class 整成一个 Bean 的,对于 Bean 本身来说是不知道的,当然也不需要知道,也就是 Bean 对容器的存在是无感的。ZpT28资讯网——每日最新资讯28at.com

但是有时候我们可能会遇到一些场景,这些场景让我们去感知容器的存在,松哥举几个例子:ZpT28资讯网——每日最新资讯28at.com

  1. Spring 容器提供的功能不止 IoC、AOP 这些,常见的 I18N 也是 Spring 的能力之一,如果我们想要在自己的 Bean 中去使用 I18N,那就得去找 Spring,这样就感知到了 Spring 容器的存在了。
  2. Spring 提供了资源加载器,如果我们想要使用这个资源加载器去加载配置,那就得去找 Spring 要,这样就感知到了 Spring 容器的存在了。
  3. 想根据 beanName 去 Spring 容器中查找 Bean,那不用多说,肯定得知道 Spring 容器的存在。
  4. ...

也就是说,虽然 Spring 中的 Bean 可以不用去感知 Spring 容器的存在,但是在实际开发中,我们往往还是需要 Spring 容器提供的各种能力,这样就迫使我们的 Bean 不得不去感知到 Spring 容器的存在。ZpT28资讯网——每日最新资讯28at.com

那么 Spring 中的 Bean 如何感知到 Spring 容器的存在呢?ZpT28资讯网——每日最新资讯28at.com

1. Aware

Aware 本身就有感知的意思。ZpT28资讯网——每日最新资讯28at.com

Spring Aware 是 Spring 框架中的一个特性,它允许我们的应用程序或组件与 Spring 容器进行交互。当一个类实现了 Spring Aware 接口并注册到 Spring 容器中时,该类就能够感知到 Spring 容器的存在,并且可以获取容器的一些资源或进行一些特定的操作。ZpT28资讯网——每日最新资讯28at.com

Spring Aware 接口包括了多个子接口,每个子接口对应于不同的 Spring 容器资源或功能。ZpT28资讯网——每日最新资讯28at.com

Aware 的实现有很多,大的方向来说主要有如下一些:ZpT28资讯网——每日最新资讯28at.com

图片图片ZpT28资讯网——每日最新资讯28at.com

每一个 Aware 的作用如下:ZpT28资讯网——每日最新资讯28at.com

  • ApplicationEventPublisherAware:实现该接口的对象可以获取事件发布的能力。
  • ServletContextAware:实现该接口的对象可以获取到 ServletContext 对象。
  • MessageSourceAware:实现该接口的对象可以获取到 MessageSource 对象,MessageSource 支持多消息源,主要用于主要用于国际化。
  • ResourceLoaderAware:实现该接口的对象可以获取到一个 ResourceLoader,Spring ResourceLoader 则为我们提供了一个统一的 getResource() 方法来通过资源路径检索外部资源,例如文本文件、XML 文件、属性文件或图像文件等。
  • ApplicationStartupAware:实现该接口的对象可以获取到一个 ApplicationStartup 对象,这个比较新,是 Spring 5.3 中新推出的,通过 ApplicationStartup 可以标记应用程序启动期间的步骤,并收集有关执行上下文或其处理时间的数据。
  • NotificationPublisherAware:实现该接的对象可以获取到一个 NotificationPublisher 对象,通过该对象可以实现通知的发送。
  • EnvironmentAware:实现该接口的对象可以获取到一个 Environment 对象,通过 Environment 可以获取到容器的环境信息。
  • BeanFactoryAware:实现该接口的对象可以获取到一个 BeanFactory 对象,通过 BeanFactory 可以完成 Bean 的查询等操作。
  • ImportAware:实现该接口的对象可以获取到一个 AnnotationMetadata 对象,ImportAware 接口是需要和 @Import 注解一起使用的。在 @Import 作为元注解使用时,通过 @Import 导入的配置类如果实现了 ImportAware 接口就可以获取到导入该配置类接口的数据配置。
  • EmbeddedValueResolverAware:实现该接口的对象可以获取到一个 StringValueResolver 对象,通过 StringValueResolver 对象,可以读取到 Spring 容器中的 properties 配置的值(YAML 配置也可以)。
  • ServletConfigAware:实现该接口的对象可以获取到一个 ServletConfig 对象,不过这个似乎没什么用,我们很少自己去配置 ServletConfig。
  • LoadTimeWeaverAware:实现该接口的对象可以获取到一个 LoadTimeWeaver 对象,通过该对象可以获取加载 Spring Bean 时织入的第三方模块,如 AspectJ 等。
  • BeanClassLoaderAware:实现该接口的对象可以获取到一个 ClassLoader 对象,ClassLoader 能干嘛不需要我多说了吧。
  • BeanNameAware:实现该接口的对象可以获取到一个当前 Bean 的名称。
  • ApplicationContextAware:实现该接口的对象可以获取到一个 ApplicationContext 对象,通过 ApplicationContext 可以获取容器中的 Bean、环境等信息。

通过实现这些接口,我们可以在应用程序中获取 Spring 容器提供的各种资源,并与容器进行交互,以实现更灵活和可扩展的功能。ZpT28资讯网——每日最新资讯28at.com

2. 实践

举两个例子小伙伴们来感受下 Aware 的具体用法。ZpT28资讯网——每日最新资讯28at.com

2.1 案例

例如我想在 Bean 中感知到当前 Bean 的名字,那么我们可以按照如下方式来使用:ZpT28资讯网——每日最新资讯28at.com

@Servicepublic class UserService implements BeanNameAware {    private String beanName;    @Override    public void setBeanName(String name) {        this.beanName = name;    }    @Override    public String toString() {        return "UserService{" +                "beanName='" + beanName + '/'' +                '}';    }}

让当前 bean 实现 BeanNameAware 接口,并重写 setBeanName 方法,这个方法会在 Spring 容器初始化 Bean 的时候自动被调用,我们就可以据此获取到 bean 的名称了。ZpT28资讯网——每日最新资讯28at.com

再比如我想做一个工具 Bean,用来查找其他 Bean,那么我可以使用如下方式:ZpT28资讯网——每日最新资讯28at.com

@Componentpublic class BeanUtils implements BeanFactoryAware {    private static BeanFactory beanFactory;    @Override    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {        this.beanFactory = beanFactory;    }    public static  <T> T getBean(Class<T> clazz) {        return (T) beanFactory.getBean(clazz);    }}

让当前 Bean 实现 BeanFactoryAware 接口并重写 setBeanFactory 方法,在系统初始化当前 Bean 的时候,会自动调用 setBeanFactory 方法,进而将 beanFactory 变量传进来。ZpT28资讯网——每日最新资讯28at.com

2.2 原理

当 Spring 容器创建一个 Bean 的时候,大致的流程是创建实例对象 -> 属性填充 -> Bean 初始化ZpT28资讯网——每日最新资讯28at.com

最后这个 Bean 的初始化,就是调用 init 方法、afterPropertiesSet 方法以及 BeanPostProcessor 中的方法的,如下:ZpT28资讯网——每日最新资讯28at.com

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { invokeAwareMethods(beanName, bean); Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) {  wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try {  invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) {  throw new BeanCreationException(    (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex); } if (mbd == null || !mbd.isSynthetic()) {  wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean;}

在这个方法一进来,首先有一个 invokeAwareMethods,这个就是用来触发 Aware 的,来看下:ZpT28资讯网——每日最新资讯28at.com

private void invokeAwareMethods(String beanName, Object bean) { if (bean instanceof Aware) {  if (bean instanceof BeanNameAware beanNameAware) {   beanNameAware.setBeanName(beanName);  }  if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {   ClassLoader bcl = getBeanClassLoader();   if (bcl != null) {    beanClassLoaderAware.setBeanClassLoader(bcl);   }  }  if (bean instanceof BeanFactoryAware beanFactoryAware) {   beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);  } }}

小伙伴们可以看到,BeanNameAware、BeanClassLoaderAware 以及 BeanFactoryAware 这三种类型的 Aware 是在这里触发的。ZpT28资讯网——每日最新资讯28at.com

每种 Aware 因为功能不同,因此作用的时机也不同。ZpT28资讯网——每日最新资讯28at.com

invokeAwareMethods 方法执行完毕之后,接下来是执行 applyBeanPostProcessorsBeforeInitialization 方法,这个我们之前分析过,这个方法最终会触发 BeanPostProcessor#postProcessBeforeInitialization 方法的执行,而 BeanPostProcessor 有一个子类专门处理 Aware 的,就是 ApplicationContextAwareProcessor:ZpT28资讯网——每日最新资讯28at.com

@Override@Nullablepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||   bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||   bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||   bean instanceof ApplicationStartupAware)) {  return bean; } invokeAwareInterfaces(bean); return bean;}private void invokeAwareInterfaces(Object bean) { if (bean instanceof Aware) {  if (bean instanceof EnvironmentAware environmentAware) {   environmentAware.setEnvironment(this.applicationContext.getEnvironment());  }  if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {   embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);  }  if (bean instanceof ResourceLoaderAware resourceLoaderAware) {   resourceLoaderAware.setResourceLoader(this.applicationContext);  }  if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {   applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);  }  if (bean instanceof MessageSourceAware messageSourceAware) {   messageSourceAware.setMessageSource(this.applicationContext);  }  if (bean instanceof ApplicationStartupAware applicationStartupAware) {   applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());  }  if (bean instanceof ApplicationContextAware applicationContextAware) {   applicationContextAware.setApplicationContext(this.applicationContext);  } }}

大家看下,这七种类型的 Aware 是在这里被触发的。ZpT28资讯网——每日最新资讯28at.com

另外像 ImportAware 是在 ImportAwareBeanPostProcessor#postProcessBeforeInitialization 方法中处理的;LoadTimeWeaverAware 是在 、LoadTimeWeaverAwareProcessor#postProcessBeforeInitialization 方法中处理的。ZpT28资讯网——每日最新资讯28at.com

基本上,大部分的 Aware 接口都是在 BeanPostProcessor 中处理的。ZpT28资讯网——每日最新资讯28at.com

ZpT28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-16740-0.html如何让 Bean 深度感知 Spring 容器

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 用 Java 深入研究树,你了解多少?

下一篇: 如何在C#客户端程序中无缝集成Python算法

标签:
  • 热门焦点
  • 天猫精灵Sound Pro体验:智能音箱没有音质?来听听我的

    这几年除了手机作为智能生活终端最主要的核心之外,第二个可以成为中心点的产品是什么?——是智能音箱。 手机在执行命令的时候有两种操作方式,手和智能语音助手,而智能音箱只
  • 6月iOS设备好评榜:第一蝉联榜首近一年

    作为安兔兔各种榜单里变化最小的那个,2023年6月的iOS好评榜和上个月相比没有任何排名上的变化,仅仅是部分设备好评率的下降,长年累月的用户评价和逐渐退出市场的老款机器让这
  • 三言两语说透设计模式的艺术-简单工厂模式

    一、写在前面工厂模式是最常见的一种创建型设计模式,通常说的工厂模式指的是工厂方法模式,是使用频率最高的工厂模式。简单工厂模式又称为静态工厂方法模式,不属于GoF 23种设计
  • Rust中的高吞吐量流处理

    作者 | Noz编译 | 王瑞平本篇文章主要介绍了Rust中流处理的概念、方法和优化。作者不仅介绍了流处理的基本概念以及Rust中常用的流处理库,还使用这些库实现了一个流处理程序
  • K8S | Service服务发现

    一、背景在微服务架构中,这里以开发环境「Dev」为基础来描述,在K8S集群中通常会开放:路由网关、注册中心、配置中心等相关服务,可以被集群外部访问;图片对于测试「Tes」环境或者
  • 8月见!小米MIX Fold 3获得3C认证:支持67W快充

    这段时间以来,包括三星、一加、荣耀等等有不少品牌旗下的最新折叠屏旗舰都得到了不少爆料,而小米新一代折叠屏旗舰——小米MIX Fold 3此前也屡屡被传
  • 小米MIX Fold 3配置细节曝光:搭载领先版骁龙8 Gen2+罕见5倍长焦

    这段时间以来,包括三星、一加、荣耀等等有不少品牌旗下的最新折叠屏旗舰都得到了不少爆料,而小米新一代折叠屏旗舰——小米MIX Fold 3此前也屡屡被传
  • iQOO Neo8系列或定档5月23日:首发天玑9200+ 安卓跑分王者

    去年10月,iQOO推出了iQOO Neo7系列机型,不仅搭载了天玑9000+,而且是同价位唯一一款天玑9000+直屏旗舰,一经上市便受到了用户的广泛关注。在时隔半年后,
  • Windows 11发布,微软一改往常对老机型开放的态度

    距离 Windows 11 发布已经过去一周,在过去一周里,很多数码爱好者围绕其对 Android 应用的支持、对老机型的升级问题展开了激烈讨论。与以往不同的是,在这次大
Top