我们在谈到 Spring 解耦能力的时候,大部分其实是在讲 Spring 的 IOC 实现控制反转和依赖注入。但在 Spring 的思想中,解耦并不只是业务代码间的解耦,还包括业务代码与框架间的解耦,Spring 想要做到业务代码对框架的无感知。所以 Spring 有意识的隔离了框架代码和业务代码,正常情况下,我们在业务代码中是无法感知和使用 Spring 框架的一些方法的。
这也带来了一个问题,那就是如果我们真的需要使用 Spring 一些方法,比如获得上下文,比如获得 Bean 容器,这时应该怎么办呢?Spring 提供了一种感知 Spring 框架功能的能力,那就是 Aware 接口。使用 Aware 接口,我们基本可以获得 Spring 所有的核心对象,代价是业务代码和 Spring 框架强耦合。
Aware 接口解决的核心问题是如何在业务代码中获得 Spring 框架内部对象的问题。
Aware 接口用做标记使用,实现该接口就表明需要使用 Spring 框架中的一些对象。
public interface Aware {}
Spring 并不会一股脑的将所有的对象都给到实现了 Aware 接口的类,这也不符合迪米特法则。所以 Aware 接口有很多的子接口,这些子接口表明需要使用的 Spring 资源。比如 BeanNameAware,表明需要知道该类的实例在 Spring 容器中的名称,这个接口中的 setBeanName 方法将由 Spring 调用,将 bean 名称传递给实现了该接口的类。
public interface BeanNameAware extends Aware {
void setBeanName(String name);
}
如下是使用示例,可以看出,对象获得了 bean 的名称,并将其存储为成员变量。
@Component
public class AwareDemo implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
除了 BeanNameAware 外,Spring 还内置了很多 Aware 接口的子接口。比如
- BeanFactoryAware,顾名思义,获取 Spring 容器 beanFactory;ApplicationContextAware,获取当前的applicationContext;
- ApplicationEventPulisherAware,获取应用事件发布器,可以用来发布事件;EnvironmentAware,获取环境相关信息,如属性、配置信息等。
Aware 接口家族很大,使用的方式也相同,就不一一列举了。
Spring 是在什么时候执行 Aware 接口的 setXXX 方法,将框架对象传入的呢?
这里分 2 种情况:
-
BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 这 3 个接口的实现类的 bean 在被 Spring 框架初始化时,被 Spring 框架调用了它们的 setXxx 方法,传入了所需的对象;
-
其它的 Aware 接口的子接口都是通过 Spring 容器的 BeanPostProcessor(后置处理器)在 bean 的创建和初始化之后,被传入的所需的对象。
网友评论