SpringContextUtils 工具類實現
下面是一個完整的 Spring 上下文工具類實現,用于從 Spring 容器中獲取 Bean。這個工具類考慮了線程安全、性能優化和易用性,并提供了多種獲取 Bean 的方式。
完整實現代碼
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;import java.util.Map;/*** Spring 上下文工具類,用于獲取容器中的Bean* * 功能包括:* 1. 獲取ApplicationContext* 2. 通過名稱獲取Bean* 3. 通過類型獲取Bean* 4. 通過名稱和類型獲取Bean* 5. 獲取指定類型的所有Bean* 6. 獲取當前環境配置*/
@Component
public class SpringContextUtils implements ApplicationContextAware {/*** 靜態ApplicationContext*/private static ApplicationContext applicationContext;/*** 設置ApplicationContext*/@Overridepublic void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException {if (SpringContextUtils.applicationContext == null) {SpringContextUtils.applicationContext = applicationContext;}}/*** 獲取ApplicationContext*/public static ApplicationContext getApplicationContext() {checkApplicationContext();return applicationContext;}/*** 通過名稱獲取Bean* @param name Bean名稱* @return Bean實例*/@SuppressWarnings("unchecked")public static <T> T getBean(String name) {checkApplicationContext();return (T) applicationContext.getBean(name);}/*** 通過類型獲取Bean* @param clazz Bean類型* @return Bean實例*/public static <T> T getBean(Class<T> clazz) {checkApplicationContext();return applicationContext.getBean(clazz);}/*** 通過名稱和類型獲取Bean* @param name Bean名稱* @param clazz Bean類型* @return Bean實例*/public static <T> T getBean(String name, Class<T> clazz) {checkApplicationContext();return applicationContext.getBean(name, clazz);}/*** 獲取指定類型的所有Bean* @param clazz Bean類型* @return Bean名稱與實例的映射*/public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {checkApplicationContext();return applicationContext.getBeansOfType(clazz);}/*** 獲取當前環境配置* @param key 配置鍵* @return 配置值*/public static String getProperty(String key) {checkApplicationContext();return applicationContext.getEnvironment().getProperty(key);}/*** 檢查ApplicationContext是否已注入*/private static void checkApplicationContext() {if (applicationContext == null) {throw new IllegalStateException("ApplicationContext未注入,請在Spring配置中定義SpringContextUtils");}}
}
功能說明
1. 核心功能
- 獲取 ApplicationContext:
getApplicationContext()
- 通過名稱獲取 Bean:
getBean(String name)
- 通過類型獲取 Bean:
getBean(Class<T> clazz)
- 通過名稱和類型獲取 Bean:
getBean(String name, Class<T> clazz)
- 獲取指定類型的所有 Bean:
getBeansOfType(Class<T> clazz)
- 獲取環境配置:
getProperty(String key)
2. 線程安全性
- 使用靜態變量存儲 ApplicationContext,保證全局唯一
- 通過
@Component
注解讓 Spring 管理工具類實例 - 實現
ApplicationContextAware
接口自動注入上下文
3. 異常處理
- 檢查 ApplicationContext 是否已注入,未注入時拋出明確異常
- 使用
@Nullable
注解標記可為空的參數 - 添加泛型支持,減少類型轉換
使用示例
1. 基本使用
// 獲取ApplicationContext
ApplicationContext context = SpringContextUtils.getApplicationContext();// 通過名稱獲取Bean
UserService userService = SpringContextUtils.getBean("userService");// 通過類型獲取Bean
UserService userService = SpringContextUtils.getBean(UserService.class);// 通過名稱和類型獲取Bean
UserService userService = SpringContextUtils.getBean("userService", UserService.class);
2. 獲取所有同類型Bean
// 獲取所有實現UserService接口的Bean
Map<String, UserService> userServices = SpringContextUtils.getBeansOfType(UserService.class);userServices.forEach((name, service) -> {System.out.println("Bean名稱: " + name + ", 實例: " + service);
});
3. 獲取環境配置
// 獲取application.properties/yml中的配置
String appName = SpringContextUtils.getProperty("spring.application.name");
String serverPort = SpringContextUtils.getProperty("server.port");
高級用法
1. 在非Spring管理的類中使用
public class NonSpringClass {public void someMethod() {// 獲取Spring容器中的BeanUserRepository repository = SpringContextUtils.getBean(UserRepository.class);repository.save(new User());}
}
2. 在靜態方法中使用
public class UtilityClass {public static void doSomething() {// 靜態方法中獲取BeanEmailService emailService = SpringContextUtils.getBean(EmailService.class);emailService.send("test@example.com", "Hello");}
}
3. 在JUnit測試中使用
@SpringBootTest
public class UserServiceTest {@Testpublic void testGetUser() {// 在測試中獲取BeanUserService userService = SpringContextUtils.getBean(UserService.class);User user = userService.getUserById(1L);assertNotNull(user);}
}
實現原理
-
ApplicationContextAware 接口:
- Spring 會在初始化時自動調用
setApplicationContext
方法 - 將 ApplicationContext 注入到工具類的靜態變量中
- Spring 會在初始化時自動調用
-
靜態方法訪問:
- 所有方法都是靜態的,方便在任何地方調用
- 內部檢查 ApplicationContext 是否已初始化
-
泛型支持:
- 減少顯式類型轉換,提高代碼安全性
- 編譯器會檢查類型是否匹配
注意事項
-
初始化時機:
- 確保 Spring 容器完全初始化后再使用工具類
- 不要在 Bean 的構造方法中使用,因為此時 Bean 還未完全初始化
-
單元測試:
- 在測試中需要先啟動 Spring 上下文
- 可以使用
@SpringBootTest
注解
-
多線程安全:
- ApplicationContext 是線程安全的
- 工具類本身不包含可變狀態,也是線程安全的
-
替代方案:
- 在 Spring Boot 中可以直接使用依賴注入
- 這個工具類主要用在無法使用依賴注入的場景
擴展功能
如果需要更多功能,可以擴展以下方法:
/*** 獲取當前環境profile*/
public static String[] getActiveProfiles() {checkApplicationContext();return applicationContext.getEnvironment().getActiveProfiles();
}/*** 判斷當前是否是指定環境*/
public static boolean isProfileActive(String profile) {checkApplicationContext();String[] activeProfiles = getActiveProfiles();return Arrays.asList(activeProfiles).contains(profile);
}/*** 發布事件*/
public static void publishEvent(Object event) {checkApplicationContext();applicationContext.publishEvent(event);
}
這個 SpringContextUtils 工具類提供了一種簡潔的方式來訪問 Spring 容器中的 Bean,特別適合在非 Spring 管理的類中獲取 Spring Bean 的場景。