Quarkus实现类似WebLogic虚拟Web目录的资源覆盖功能
在Quarkus中实现WebLogic风格的虚拟Web目录覆盖逻辑
你的需求是让请求优先读取指定磁盘目录中的资源,不存在时回退到应用JAR内的资源,单独使用undertow-handlers.conf的resource指令无法实现回退,以下是两种可行方案:
方案1:通过Undertow处理器链快速实现
利用Undertow的chain指令按顺序尝试资源来源,先检查磁盘目录,再回退到类路径资源:
- 编辑
src/main/resources/META-INF/undertow-handlers.conf,添加以下配置:
path-prefix('/some/path/to') -> chain( resource(location='/真实磁盘虚拟目录路径', allow-listing=true), resource(location='classpath:/META-INF/resources/some/path/to', allow-listing=true) )
- 第一个
resource指向你要优先读取的磁盘文件夹,替换/真实磁盘虚拟目录路径为实际路径 - 第二个
resource对应JAR内的资源路径,Quarkus默认把src/main/resources下的内容打包到classpath:/META-INF/resources/目录下,按需调整路径
- 若需要动态配置磁盘目录路径,可在
application.properties中定义变量:
quarkus.virtual-web-dir=/真实磁盘虚拟目录路径
然后在undertow-handlers.conf中引用变量:
path-prefix('/some/path/to') -> chain( resource(location='${quarkus.virtual-web-dir}', allow-listing=true), resource(location='classpath:/META-INF/resources/some/path/to', allow-listing=true) )
方案2:自定义ResourceManager(复杂场景适配)
如果需要更灵活的逻辑(比如动态切换目录、权限校验等),可以自定义Undertow的资源管理器:
- 编写自定义资源管理器类,组合磁盘和类路径资源读取逻辑:
import io.undertow.server.handlers.resource.ClassPathResourceManager; import io.undertow.server.handlers.resource.FileResourceManager; import io.undertow.server.handlers.resource.Resource; import io.undertow.server.handlers.resource.ResourceManager; import io.undertow.server.handlers.resource.ResourceChangeListener; import java.io.IOException; import java.nio.file.Paths; public class FallbackResourceManager implements ResourceManager { private final ResourceManager diskResourceManager; private final ResourceManager classPathResourceManager; public FallbackResourceManager(String virtualDirPath, String classPathBase) { this.diskResourceManager = new FileResourceManager(Paths.get(virtualDirPath).toFile(), 1024); this.classPathResourceManager = new ClassPathResourceManager(Thread.currentThread().getContextClassLoader(), classPathBase); } @Override public Resource getResource(String path) throws IOException { // 优先读取磁盘资源 Resource diskResource = diskResourceManager.getResource(path); if (diskResource != null && diskResource.exists()) { return diskResource; } // 磁盘不存在则读取类路径资源 return classPathResourceManager.getResource(path); } @Override public boolean isResourceChangeListenerSupported() { return diskResourceManager.isResourceChangeListenerSupported() || classPathResourceManager.isResourceChangeListenerSupported(); } @Override public void registerResourceChangeListener(ResourceChangeListener listener) { diskResourceManager.registerResourceChangeListener(listener); classPathResourceManager.registerResourceChangeListener(listener); } @Override public void removeResourceChangeListener(ResourceChangeListener listener) { diskResourceManager.removeResourceChangeListener(listener); classPathResourceManager.removeResourceChangeListener(listener); } @Override public void close() throws IOException { diskResourceManager.close(); classPathResourceManager.close(); } }
- 编写Undertow配置类,注册自定义资源管理器:
import io.quarkus.undertow.runtime.UndertowDeploymentInfoCustomizer; import io.undertow.servlet.api.DeploymentInfo; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.eclipse.microprofile.config.inject.ConfigProperty; @ApplicationScoped public class VirtualWebDirConfig implements UndertowDeploymentInfoCustomizer { @Inject @ConfigProperty(name = "quarkus.virtual-web-dir") String virtualDirPath; @Override public void customize(DeploymentInfo deploymentInfo) { // 为指定路径前缀绑定自定义资源管理器 deploymentInfo.addResourceManager( new FallbackResourceManager(virtualDirPath, "/META-INF/resources/some/path/to"), "/some/path/to" ); } }
- 在
application.properties中配置磁盘虚拟目录:
quarkus.virtual-web-dir=/真实磁盘虚拟目录路径
注意事项
- 确保Quarkus进程对磁盘虚拟目录有读取权限
- 类路径资源路径需与JAR内实际资源位置对应,比如
src/main/resources/some/path/to下的文件对应/META-INF/resources/some/path/to - 测试时可先在磁盘目录放入目标文件,验证优先读取逻辑;删除磁盘文件后,确认请求会返回JAR内的资源
内容的提问来源于stack exchange,提问作者Noam
相关产品推荐
相关产品推荐

