深入理解Spring IOC之扩展篇(四)、Aware接口

简介: 深入理解Spring IOC之扩展篇(四)、Aware接口

本篇讲的是Spring中的Aware接口,也应该是整个系列中最简单的一篇了,但是简单并不代表这玩意不重要,我们很多时候还是会用Aware接口去为我们做事情的。

我们知道,使用了Spring容器之后,我们创建对象这件事情完完全全的交给了Spring,在创建好了之后我们直接拿来用就可以了,容器内的东西对于我们的bean来说完全是透明的。为了让我们的bean可以感知到容器内的一些东西,所以Spring为我们提供了Aware接口,看过我之前文章的小伙伴肯定都知道,在初始化bean的时候有这么一段代码:


private void invokeAwareMethods(final String beanName, final Object bean) {
    // 所谓的xxxAware,就是让这个bean和xxx产生关联
    if (bean instanceof Aware) {
      // 设置名称
      if (bean instanceof BeanNameAware) {
        ((BeanNameAware) bean).setBeanName(beanName);
      }
      // 类加载器
      if (bean instanceof BeanClassLoaderAware) {
        ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
      }
      // 我们有时候使用BeanFactoryAware去拿BeanFactory,就是在这步设置的
      if (bean instanceof BeanFactoryAware) {
        ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
      }
    }
  }


上面这段代码便是处理其中三种Aware的逻辑,我们分别看看这三种Aware的代码:

BeanNameAware:


public interface BeanNameAware extends Aware {
  void setBeanName(String name);
}


BeanClassLoaderAware:


public interface BeanClassLoaderAware extends Aware {
  void setBeanClassLoader(ClassLoader classLoader);
}


BeanFactoryAware:


public interface BeanFactoryAware extends Aware {
  void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}


这三个Aware其实也就是让我们的bean可以知道自己名字,自己的ClassLoader是哪个,加载自己的BeanFactory是哪个,结合我们上面的代码我们知道其实设置这三个Aware是在bean的生命周期内设置的。

那么还有哪些常见的Aware呢?我自己最常用的一个就是ApplicationContextAware,这个接口的代码我就不贴出来了,因为和上面是一样的,就一个set方法而已,那么又是在哪个地方给我们的bean执行了setApplicationContext的方法呢?我们之前文章中介绍AbstractApplicationContext的refresh方法的时候,其中有个prepareBeanFactory方法,这个方法中有这么一句代码:


1686812318527.png


只看画红框的地方就行了,我们可以看到,spring在这里增加了一个ApplicationContextAwareProcessor,这个玩意的本质上是个BeanPostProcessor,那么这玩意干了什么事情呢?我们一起来看下它的代码:


@Override
  public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
    AccessControlContext acc = null;
    if (System.getSecurityManager() != null &&
        (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
            bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
            bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
    }
    //特权执行和普通执行下面的方法
    if (acc != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
          invokeAwareInterfaces(bean);
          return null;
        }
      }, acc);
    }
    else {
      invokeAwareInterfaces(bean);
    }
    return bean;
  }
  // 上面调用了这个
  private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof Aware) {
      if (bean instanceof EnvironmentAware) {
        ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
      }
      if (bean instanceof EmbeddedValueResolverAware) {
        ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
            new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
      }
      if (bean instanceof ResourceLoaderAware) {
        ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
      }
      if (bean instanceof ApplicationEventPublisherAware) {
        ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
      }
      if (bean instanceof MessageSourceAware) {
        ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
      }
      if (bean instanceof ApplicationContextAware) {
        ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
    }
  }


这个类只是实现了前置处理这个方法,前置处理什么时候执行的我就不说了,看到这里的人应该是清楚的。这段代码你看我连注释都很少,因为真的很简单,就是检测你是不是实现了这个Aware接口,如果实现了,就给你set上相应的对象而已。其中invokeAwareInterfaces中还有几个其他的Aware,但是说真的,这几个用的都不多,我自己都很少见过业务中使用这几个的,如果读者有兴趣可以自己研究下这几个。

目录
相关文章
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
XML 人工智能 Java
Spring IOC 到底是什么?
IOC(控制反转)是一种设计思想,主要用于解耦代码,简化依赖管理。其核心是将对象的创建和管理交给容器处理,而非由程序直接硬编码实现。通过IOC,开发者无需手动new对象,而是由框架负责实例化、装配和管理依赖对象。常见应用如Spring框架中的BeanFactory和ApplicationContext,它们实现了依赖注入和动态管理功能,提升了代码的灵活性与可维护性。
367 1
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
501 18
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
Java 容器 Spring
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
|
消息中间件 缓存 Java
spring4.1.8扩展实战之三:广播与监听
提到广播与监听,我们常常会想到RabbitMQ、Kafka等消息中间件,这些常用于分布式系统中多个应用之间,有时候应用自身内部也有广播和监听的需求(例如某个核心数据发生变化后,有些业务模块希望立即被感知),这时候spring提供的基于ApplicationContext的广播与监听就派上用场了,接下来我们从原理到实践,来了解spring提供的这套机制吧
575 0
spring4.1.8扩展实战之三:广播与监听
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1583 0
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1530 0
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
663 0
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
1272 0