如何让Java类动态实现不同包路径的WebResourceTransformerFactory接口?
Confluence 8-9版本WebResourceTransformerFactory兼容方案
首先明确:Java反射无法让一个类在运行时动态实现不同的接口。类的接口实现信息是编译期写入字节码的,运行时无法修改已加载类的继承/实现结构,所以靠反射直接实现动态接口适配不可行。
下面是两种可行的兼容方案,基于隔离接口实现+动态加载的思路:
方案一:适配器模式+多实现类分离
把业务逻辑和接口实现解耦,写一个通用的逻辑类,再分别为新旧接口写适配实现类,通过插件配置根据Confluence版本动态加载对应类。
步骤1:提取通用业务逻辑
将原本Transformer里的核心逻辑抽离成独立类,不依赖任何版本的接口:
// 通用转换逻辑,与Confluence版本无关 public class TransformerCore { // 这里放原本的业务代码 public String processContent(String content) { // Do something... return transformedContent; } }
步骤2:分别实现新旧接口
旧版本(Confluence 8)适配类
import com.atlassian.plugin.webresource.transformer.WebResourceTransformer; import com.atlassian.plugin.webresource.transformer.WebResourceTransformerFactory; import java.util.Map; import java.io.Reader; import java.io.StringReader; public class OldTransformerAdapter implements WebResourceTransformerFactory { private final TransformerCore core = new TransformerCore(); @Override public WebResourceTransformer createTransformer(Map<String, String> params) { return (reader, context) -> { // 读取输入内容 String content = readReaderToString(reader); // 调用核心逻辑处理 String processed = core.processContent(content); // 返回处理后的结果 return new StringReader(processed); }; } // 工具方法:将Reader转为String private String readReaderToString(Reader reader) { // 实现读取逻辑... } }
新版本(Confluence 9+)适配类
import com.atlassian.webresource.spi.transformer.WebResourceTransformer; import com.atlassian.webresource.spi.transformer.WebResourceTransformerFactory; import java.util.Map; import java.io.Reader; import java.io.StringReader; public class NewTransformerAdapter implements WebResourceTransformerFactory { private final TransformerCore core = new TransformerCore(); @Override public WebResourceTransformer createTransformer(Map<String, String> params) { return input -> { String content = readReaderToString(input); String processed = core.processContent(content); return new StringReader(processed); }; } private String readReaderToString(Reader reader) { // 同旧版本的工具方法实现 } }
步骤3:插件配置动态加载
在atlassian-plugin.xml中,利用Confluence的版本条件配置加载对应的适配器:
<!-- 适配Confluence 8及以下版本 --> <web-resource-transformer key="my-transformer-old" class="com.yourcompany.plugin.OldTransformerAdapter" condition="com.atlassian.confluence.version < 9.0.0"> <!-- 配置参数 --> </web-resource-transformer> <!-- 适配Confluence 9及以上版本 --> <web-resource-transformer key="my-transformer-new" class="com.yourcompany.plugin.NewTransformerAdapter" condition="com.atlassian.confluence.version >= 9.0.0"> <!-- 配置参数 --> </web-resource-transformer>
方案二:OSGi动态导入+动态代理(进阶)
如果两个版本的接口方法签名完全一致,可以通过OSGi动态导入包结合Java动态代理实现单类适配,但复杂度较高:
步骤1:pom.xml配置动态依赖
<dependency> <groupId>com.atlassian.confluence</groupId> <artifactId>confluence-web-resources</artifactId> <version>[8.0.0,10.0.0)</version> <scope>provided</scope> </dependency> <!-- 动态导入两个包路径 --> <Import-Package> com.atlassian.plugin.webresource.transformer;resolution:=optional, com.atlassian.webresource.spi.transformer;resolution:=optional, * </Import-Package>
步骤2:写动态代理生成类
import java.lang.reflect.Proxy; import java.util.Map; import java.io.Reader; import java.io.StringReader; public class TransformerProxyFactory { private static final TransformerCore CORE = new TransformerCore(); public static Object createTransformerFactory() throws Exception { // 先尝试加载新版本接口 Class<?> factoryInterface; try { factoryInterface = Class.forName("com.atlassian.webresource.spi.transformer.WebResourceTransformerFactory"); } catch (ClassNotFoundException e) { // 加载失败则用旧版本接口 factoryInterface = Class.forName("com.atlassian.plugin.webresource.transformer.WebResourceTransformerFactory"); } // 生成动态代理 return Proxy.newProxyInstance( factoryInterface.getClassLoader(), new Class[]{factoryInterface}, (proxy, method, args) -> { if ("createTransformer".equals(method.getName())) { Map<String, String> params = (Map<String, String>) args[0]; // 获取Transformer接口类型 Class<?> transformerInterface = Class.forName( factoryInterface.getPackage().getName() + ".WebResourceTransformer" ); // 生成Transformer的代理 return Proxy.newProxyInstance( transformerInterface.getClassLoader(), new Class[]{transformerInterface}, (transProxy, transMethod, transArgs) -> { if ("transform".equals(transMethod.getName())) { // 处理转换逻辑,调用核心类 Reader input = (Reader) transArgs[0]; String content = readReaderToString(input); String processed = CORE.processContent(content); return new StringReader(processed); } return transMethod.invoke(null, transArgs); } ); } return method.invoke(null, args); } ); } private static String readReaderToString(Reader reader) { // 实现读取逻辑... } }
步骤3:插件配置加载代理
在atlassian-plugin.xml中配置工厂类,通过静态方法获取代理实例:
<web-resource-transformer key="my-transformer" class="com.yourcompany.plugin.TransformerProxyFactory" factory-method="createTransformerFactory"> <!-- 配置参数 --> </web-resource-transformer>
注意事项
- 依赖配置要使用版本范围,确保同时兼容8和9版本的Confluence依赖
- 测试时要分别在Confluence 8和9环境下验证功能,避免接口方法签名差异导致的问题
- 优先选择方案一,代码更直观,维护成本更低;方案二适合接口方法完全一致的场景,复杂度较高
内容的提问来源于stack exchange,提问作者Leon kong
相关产品推荐
相关产品推荐

