基于MicroProfile配置的CDI工厂:无限定符注入StorageEngine
无需限定符动态注入StorageEngine实现方案
可以实现,不需要给注入点添加任何限定符,只需通过以下步骤完成配置驱动的实例匹配:
1. 给每个StorageEngine实现类添加@Named注解
为每个实现类指定与配置值对应的名称,让生产者能通过配置值精准匹配实例:
import jakarta.inject.Named; import jakarta.inject.Singleton; @Named("local-filesystem") // 对应配置默认值 @Singleton public class LocalFileSystemEngine implements StorageEngine { // 实现方法... } @Named("dropbox") @Singleton public class DropboxEngine implements StorageEngine { // 实现方法... } @Named("google-drive") @Singleton public class GoogleDriveEngine implements StorageEngine { // 实现方法... }
2. 完善StorageProducer的getStorageEngine方法
通过CDI的Instance.select()结合Named限定符,根据配置的engineType获取对应实例,同时处理配置无效的异常情况:
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.inject.Any; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.Produces; import jakarta.inject.Inject; import jakarta.inject.Named; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ApplicationScoped public class StorageProducer { private static final Logger logger = LoggerFactory.getLogger(StorageProducer.class); @Inject @ConfigProperty(name = "storage.engine-type", defaultValue = "local-filesystem") private String engineType; @Inject @Any private Instance<StorageEngine> storageEngineInstance; @Produces public StorageEngine getStorageEngine() { // 根据配置值选择对应Named实例 Instance<StorageEngine> selectedInstance = storageEngineInstance.select(NamedLiteral.of(engineType)); if (selectedInstance.isResolvable()) { logger.info("启用存储引擎: {}", engineType); return selectedInstance.get(); } // 配置无效时回退到默认引擎 logger.warn("配置的存储引擎{}不存在,切换为默认的local-filesystem", engineType); Instance<StorageEngine> defaultInstance = storageEngineInstance.select(NamedLiteral.of("local-filesystem")); return defaultInstance.get(); } }
注:
NamedLiteral是CDI内置工具类,用于动态创建@Named限定符实例,无需额外依赖。
3. 验证注入点代码
你的FileServlet注入代码完全不需要修改,直接使用@Inject即可获取匹配配置的实例:
@MultipartConfig @WebServlet(urlPatterns = "/file") public class FileServlet extends HttpServlet { @Inject private StorageEngine storageEngine; // 实现业务方法... }
原理说明
- 每个实现类的
@Named注解相当于给实例打上名称标签,CDI容器会按标签管理这些实例。 - 生产者类根据配置值动态选择对应标签的实例,并将其作为默认的StorageEngine类型提供给容器。
- 注入点直接请求
StorageEngine类型时,容器会自动使用生产者产出的匹配实例,无需额外限定符。
内容的提问来源于stack exchange,提问作者mah454
相关产品推荐
相关产品推荐

