实际上,[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50)方法确实会被Spring容器自动调用,让我来解释一下这个过程是如何发生的。
当一个类实现了ApplicationContextAware接口时,Spring框架会自动识别这一点,并在Bean初始化过程中调用[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50)方法。这个过程是由Spring容器内部的机制完成的,不需要显式的调用。
具体流程如下:
- Bean实例化:Spring容器创建[LockInfoHandleFactory](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L23-L52) Bean实例
- Aware接口检测:Spring检测到该Bean实现了
ApplicationContextAware接口 - 自动调用:Spring容器自动调用[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50)方法,传入当前的ApplicationContext实例
- 依赖注入完成:此时[applicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L30-L31)字段已经被赋值,可以在其他方法中使用
这个工作机制依赖于Spring的以下特性:
- Aware接口处理机制:Spring内部有一套机制来处理各种Aware接口(如ApplicationContextAware、BeanNameAware等)
- BeanPostProcessor:Spring使用BeanPostProcessor来处理Aware接口,在适当的时机调用相应的方法
查看一下这个类是否被注册为Spring Bean:
现在我可以清楚地回答你的问题了。你提到的[selectedCode](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L42-L51)中的[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50)方法确实是会被调用的,只是不是通过显式的代码调用,而是由Spring框架自动调用的。
Spring容器如何自动调用setApplicationContext
正如我在前面解释的,当Spring容器创建并初始化一个实现了ApplicationContextAware接口的Bean时,它会自动检测到这个接口,并在适当的时候调用[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50)方法。
LockInfoHandleFactory是如何注册为Spring Bean的
通过查看代码,我们可以看到在[RedissonCommonAutoConfiguration](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/config/RedissonCommonAutoConfiguration.java#L35-L136)类中有以下配置:
@Bean
public LockInfoHandleFactory lockInfoHandleFactory(){
return new LockInfoHandleFactory();
}这表明[LockInfoHandleFactory](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L23-L52)被注册为一个Spring Bean。
完整的流程
- Bean注册:通过[RedissonCommonAutoConfiguration.lockInfoHandleFactory()](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/config/RedissonCommonAutoConfiguration.java#L134-L135)方法,[LockInfoHandleFactory](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L23-L52)被注册为Spring Bean
- Bean实例化:Spring容器创建[LockInfoHandleFactory](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L23-L52)实例
- Aware接口处理:Spring检测到该Bean实现了
ApplicationContextAware接口 - 自动调用:Spring框架自动调用[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50)方法,将ApplicationContext注入到[applicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L30-L31)字段中
- 正常使用:之后就可以在[getLockInfoHandle](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L37-L39)方法中使用[applicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L30-L31)来获取其他Bean了
这种方式是Spring框架的标准做法,很多Spring内置的类也是这样工作的,比如各种Aware接口的实现类。你不需要手动调用[setApplicationContext](file://D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L47-L50),Spring会帮你完成这个过程。
让我来解释一下applicationContext.getBean的调用方式。这是Spring框架中一种重要的获取Bean实例的方法。
applicationContext.getBean的调用方式详解
在[LockInfoHandleFactory](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L23-L52)类中,通过以下方式调用[getBean](file://D:\Java_projects\damai\damai-common\src\main\java\com\damai\core\SpringUtil.java#L29-L31)方法:
return applicationContext.getBean(lockInfoType, LockInfoHandle.class);这是[getBean](file://D:\Java_projects\damai\damai-common\src\main\java\com\damai\core\SpringUtil.java#L29-L31)方法的一种重载形式,让我们看看Spring中[getBean](file://D:\Java_projects\damai\damai-common\src\main\java\com\damai\core\SpringUtil.java#L29-L31)的主要调用方式:
1. 按名称获取Bean
// 通过Bean名称获取
Object bean = applicationContext.getBean("beanName");
// 通过Bean名称和类型获取(类型安全)
MyService myService = applicationContext.getBean("myService", MyService.class);2. 按类型获取Bean
// 通过类型获取Bean(要求容器中只有一个该类型的Bean)
MyService myService = applicationContext.getBean(MyService.class);
// 在LockInfoHandleFactory中的用法就是这种形式
LockInfoHandle lockInfoHandle = applicationContext.getBean(lockInfoType, LockInfoHandle.class);3. 按名称和类型获取Bean
// 通过Bean名称和类型获取(最安全的方式)
MyService myService = applicationContext.getBean("myService", MyService.class);LockInfoHandleFactory中的具体应用
在[LockInfoHandleFactory](file:///D:/Java_projects/damai/damai-redisson-framework/damai-redisson-service-framework/damai-redisson-common-framework/src/main/java/com/damai/lockinfo/factory/LockInfoHandleFactory.java#L23-L52)中,使用的是第3种方式:
public LockInfoHandle getLockInfoHandle(String lockInfoType){
return applicationContext.getBean(lockInfoType, LockInfoHandle.class);
}这里的参数含义:
lockInfoType: Bean的名称(同时也是锁信息类型的标识符)LockInfoHandle.class: 期望获取的Bean类型
这种方式的优势:
- 类型安全:确保获取的Bean是指定类型的实例
- 灵活性:通过参数动态决定获取哪个Bean
- 解耦合:工厂类不需要知道所有可能的实现类
实际使用场景
这种设计模式在以下场景中非常有用:
1. 策略模式实现
// 根据不同类型获取不同的策略实现
LockInfoHandle handle = lockInfoHandleFactory.getLockInfoHandle("repeatExecuteLimit");
// 或者
LockInfoHandle handle = lockInfoHandleFactory.getLockInfoHandle("serviceLock");2. 工厂模式实现
// 工厂类不需要硬编码所有可能的实现类
public class LockInfoHandleFactory {
public LockInfoHandle getLockInfoHandle(String type) {
// 动态获取对应类型的Bean
return applicationContext.getBean(type, LockInfoHandle.class);
}
}相关的Bean定义示例
为了让这种方法工作,需要在Spring配置中定义相应名称的Bean,例如:
@Bean("repeatExecuteLimit")
public LockInfoHandle repeatExecuteLimitLockInfoHandle() {
return new RepeatExecuteLimitLockInfoHandle();
}
@Bean("serviceLock")
public LockInfoHandle serviceLockInfoHandle() {
return new ServiceLockInfoHandle();
}这样,当调用lockInfoHandleFactory.getLockInfoHandle("repeatExecuteLimit")时,就会获取到名为"repeatExecuteLimit"且类型为[LockInfoHandle](file://D:\Java_projects\damai\damai-redisson-framework\damai-redisson-service-framework\damai-redisson-common-framework\src\main\java\com\damai\lockinfo\LockInfoHandle.java#L20-L37)的Bean。
这种设计充分利用了Spring框架的依赖注入和Bean管理能力,实现了灵活且松耦合的组件获取机制。