前言
在Spring框架中,有许多接口和类都有一个非常重要的作用——让我们能够更方便地构建应用程序和管理组件。其中,Aware接口就是其中一个非常重要的接口之一。通过实现该接口,我们可以让Spring容器感知到特定的组件和资源,并进行初始化或注入。本文将介绍Aware接口的概念、使用方法以及示例。
一、什么是 Aware 接口
Aware接口是Spring框架中的一个非常重要的接口,它定义了一些回调方法,用于让Spring容器感知到特定的组件或资源。通过实现Aware接口,我们可以让Spring容器向特定的组件注入自己所持有的一些资源,或者让Spring容器调用特定的组件方法来对其进行初始化或其他操作。这样,我们就可以更方便地管理组件和资源,将它们更好地整合到Spring应用程序中。
二、开始学习
1、新建项目,结构如下
2、添加 spring 依赖
<!-- spring 的核心依赖 -->
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
</dependencies>
3、在 service 包下新建一个 UserService 类
@Slf4j
@Service
public class UserService implements BeanNameAware {
/**
* 注入 bean 的名字
*/
private String beanName;
/**
* 容器会通过这个 set 方法将 bean 的名称注入进来
*
* @param beanName
*/
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void add() {
log.info("添加用户,使用 beanName:" + this.beanName);
}
}
BeanNameAware
是一个Spring框架提供的接口,实现该接口可以让类获取到自己在容器中的名称。在这个示例中,UserService
实现了BeanNameAware
接口,通过重写其中的setBeanName()
方法,获取了自身在容器中的名称,并保存在了beanName
字段中。这个字段虽然看似没有实际作用,但在某些场景下是比较有用的。例如,在项目中可能存在多个名字不同但功能相同的类,使用
beanName
字段就可以区分它们。又或者,在将来需要对某种类型的Bean进行特殊的处理时,也可以根据beanName
来进行判断和操作。同时,
@Slf4j
注解是Lombok库提供的注解,可以自动生成log
对象,使用log.info()
等方法输出日志信息。在这个示例中,UserService
类中的add()
方法使用了log.info()
输出了一条包含beanName
字段的日志信息。综合起来看,这段代码中的
BeanNameAware
和@Slf4j
注解,虽然看似没有实际作用,但还是提供了一些便利和可扩展性。Aware 接口(感知型接口),当 spring 容器发现某个 bean,实现了 Aware 接口以后,name 就会为这个 bean 注入一些容器核心对象,比如某些业务场景中需要得到 bean 的名字或者 id 时,可以通过此接口来获取。
4、 在 config 包下新建一个 AppConfig 类和 ApplicationContextHolder 工具类
AppConfig 类
@Configuration
@ComponentScan(basePackages = "edu.nf.ch22")
public class AppConfig {
}
AppConfig
是一个配置类,使用了@Configuration
注解来标识它是一个配置类。配置类主要用于定义和配置应用程序中的Bean,通常与Spring的IoC容器一起使用。
@ComponentScan
注解是用来指定扫描组件的基础包路径的。在这个示例中,basePackages
属性指定了需要扫描的基础包路径为edu.nf.ch22
。这意味着Spring容器会扫描该路径下的所有类,并将符合条件的类注册为Bean。通过
@ComponentScan
注解,Spring会自动扫描并创建被@Component
、@Service
、@Repository
、@Controller
等注解修饰的类的实例,并将其纳入IoC容器进行管理。
ApplicationContextHolder 工具类
public class ApplicationContextHolder implements ApplicationContextAware {
/**
* 声明容器
*/
private static ApplicationContext applicationContext;
/**
* 通过 set 方法将容器本身给注入进来
*
* @param appContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext appContext) throws BeansException {
applicationContext = appContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 封装了容器的 getBean 方法
* @param id
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String id, Class<T> clazz) {
return applicationContext.getBean(id, clazz);
}
/**
* 封装容器 getBean 方法
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz){
return applicationContext.getBean(clazz);
}
}
ApplicationContextHolder
是一个实现了ApplicationContextAware
接口的类,用于获取和管理Spring的应用上下文。首先,该类声明了一个静态的
applicationContext
字段,用于保存应用上下文对象。然后,通过实现
setApplicationContext()
方法,将应用上下文对象注入到applicationContext
字段中。当Spring容器初始化时,会自动调用setApplicationContext()
方法,并传入应用上下文对象。接下来,该类提供了两个静态方法:
getApplicationContext()
:用于获取应用上下文对象,即返回保存在applicationContext
字段中的对象。
getBean()
:封装了应用上下文的getBean()
方法,提供了两个重载版本。一个是根据id和Class类型获取Bean对象,另一个是根据Class类型获取Bean对象。这两个方法可以方便地在应用中获取被Spring管理的Bean对象。通过使用
ApplicationContextHolder
类,我们可以在任何地方获取到Spring的应用上下文对象,并使用其提供的方法获取需要的Bean对象,避免了在代码中手动获取或保持应用上下文对象的麻烦。这样可以更方便地管理和使用Spring容器中的组件。
5、在 service 包下再建一个 StuService 类
@Service
@Slf4j
public class StuService {
public void add(){
// 直接使用 ApplicationContextHolder
UserService bean = ApplicationContextHolder.getBean("userService",UserService.class);
bean.add();
}
}
在
StuService
类中,使用了ApplicationContextHolder
来获取UserService
的实例并调用其方法。首先,
StuService
类被标记为@Service
注解,表示它是一个服务组件,会被Spring容器扫描并管理。在
add()
方法中,通过ApplicationContextHolder.getBean()
方法从应用上下文中获取名为"userService"的UserService
实例,并将其赋值给bean
变量。然后,调用
bean.add()
方法,即调用UserService
实例的add()
方法。通过使用
ApplicationContextHolder.getBean()
方法,我们可以在StuService
中直接获取其他被Spring管理的Bean,而不需要依赖注入或手动创建对象。这样可以方便地在不同的组件之间进行交互和调用,提高代码的可维护性和灵活性。
6、测试
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService bean = context.getBean(UserService.class);
bean.add();
}
}
运行结果
Aware 接口(感知型接口),当 spring 容器发现某个 bean,实现了 Aware 接口以后,name 就会为这个 bean 注入一些容器核心对象,比如某些业务场景中需要得到 bean 的名字或者 id 时,可以通过此接口来获取。
三、使用 BeanNameAware、ApplicationContextAware 这两个接口的好处
BeanNameAware 接口和 ApplicationContextAware 接口是 Spring Framework 提供的 Aware 接口之一,它们分别用于在 Bean 实例化和初始化过程中获取相关的信息和资源。它们的使用可以带来以下好处:
BeanNameAware 接口的好处:
- 获取当前 Bean 在容器中的名称:通过实现 BeanNameAware 接口,可以在 Bean 初始化阶段获得当前 Bean 在容器中的名称,这样在后续的操作中可以根据名称进行进一步的处理或判断。
ApplicationContextAware 接口的好处:
- 访问容器对象:通过实现 ApplicationContextAware 接口,可以在 Bean 初始化阶段获取到 Spring 容器的上下文对象(ApplicationContext),从而可以直接使用容器提供的各种功能,如获取其他 Bean、发布事件等。
- 获取环境信息:ApplicationContext 接口继承了 EnvironmentCapable 接口,因此可以通过实现 ApplicationContextAware 接口来获取当前环境的相关信息,包括配置文件中的属性值、系统变量等。这样可以根据环境信息作出不同的处理逻辑。
综上所述,BeanNameAware 和 ApplicationContextAware 接口的使用可以让你的 Bean 在实例化和初始化过程中获得更多的信息和资源,使其能够更好地适应和利用 Spring 容器的功能。通过这些接口,你可以在 Bean 中获取到容器中的其他 Bean、环境信息等,并根据这些信息进行相应的处理和操作,增加了代码的灵活性和可扩展性。然而,在使用这些 Aware 接口时,需要注意避免过度依赖容器的实现细节,保持代码的松耦合性,以便提高代码的可测试性和可维护性。
四、gitee 案例
案例完整地址:https://gitee.com/qiu-feng1/spring-framework.git