导出Java库后无法访问NatsProperties父类扩展方法
问题描述
我正在构建一个Java库streaming-client.jar,用于客户端微服务。库中有一个继承自第三方POJO的类:
@ConditionalOnClass({Options.class}) @ConfigurationProperties(prefix = "nats.spring") public class ServerProps extends NatsProperties { public ServerProps(){ super(); } }
NatsProperties来自第三方库io.nats:nats-spring:0.5.6,且它本身继承了自动配置类。本地开发时能正常访问NatsProperties的父类方法,但将库打包成Jar给客户端应用使用时,客户端代码无法通过ServerProps调用父类方法:
ServerProps props = new ServerProps(); props.server("sdfsfsdfsdf"); // server方法无法解析
补充尝试
我试过把NatsProperties的所有方法复制到自定义类StreamingServerProperties中,但客户端调用时依然报错:
StreamingServerProperties props = new StreamingServerProperties(); props.server("serverUrl"); // Intellij提示:Cannot access io.nats.spring.boot.autoconfigure.NatsProperties
库的Build.gradle配置
plugins { id 'java-library' id 'maven-publish' id "com.github.johnrengelman.shadow" version "7.1.2" } group = 'com.dexter' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } publishing { publications { mavenJava(MavenPublication) { from components.java versionMapping { usage('java-api') { fromResolutionOf('runtimeClasspath') } usage('java-runtime') { fromResolutionResult() } } } } } tasks.named('compileJava') { inputs.files(tasks.named('processResources')) } dependencies { implementation 'io.nats:nats-spring:0.5.6' testImplementation 'org.junit.vintage:junit-vintage-engine:5.9.0' testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.3' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.0' testImplementation 'org.junit.platform:junit-platform-engine:1.9.0' testImplementation 'org.junit.platform:junit-platform-launcher:1.8.2' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' implementation('np.com.madanpokharel.embed:nats-embedded:2.1.0') } tasks.named('test') { useJUnitPlatform() }
用./gradlew build生成的Jar存在上述问题,但用shadow插件的fatJar任务生成的Jar能正常访问方法,不过Jar体积过大。
问题原因
核心问题是第三方依赖的可见性:
- 默认
build任务打包的Jar仅包含自研代码,第三方依赖不会被打包。同时用implementation声明的依赖不会传递给客户端,导致客户端编译时找不到NatsProperties的类定义,无法解析父类方法。 - 复制父类方法的尝试失败,是因为自定义类可能仍隐式依赖
NatsProperties的内部结构(比如方法返回类型、私有逻辑调用),客户端未引入nats-spring依赖,因此编译报错。
解决方案
方案1:将第三方依赖改为api声明
修改build.gradle的依赖配置,把nats-spring的implementation替换为api:
dependencies { api 'io.nats:nats-spring:0.5.6' // 替换原来的implementation // 其他依赖保持不变 }
api会将该依赖暴露给客户端应用,客户端编译时能自动获取NatsProperties的类定义,正常解析父类方法。- 这种方式不会增大库Jar体积,符合Java库常规依赖管理规范。
方案2:按需打包第三方依赖(精简shadow Jar)
如果不想让客户端引入nats-spring依赖,可通过shadow插件仅打包NatsProperties相关的必要类:
shadowJar { // 只打包NatsProperties所在的包 include 'io/nats/spring/boot/autoconfigure/**' // 可选:排除不需要的类缩小体积 exclude 'io/nats/spring/boot/autoconfigure/unused/**' // 可选:重命名包避免与客户端本地依赖冲突 relocate 'io.nats.spring.boot.autoconfigure', 'com.dexter.shaded.nats.spring.boot.autoconfigure' }
执行./gradlew shadowJar生成精简Jar,体积远小于全量fatJar。注意:如果NatsProperties依赖其他底层类,需要一并包含,否则运行时会出现ClassNotFoundException。
内容的提问来源于stack exchange,提问作者Rookie007
相关产品推荐
相关产品推荐

