java.util.ServiceLoader使用

今天在看hadoop源代的时候发现,在FileSystem中用到了java.util.ServiceLoader这个类来从配置文件中加载子类或者接口的实现类。以前从来没有使用过这个类,进去大概看了一下具体的实现。主要是从META-INF/services这个目录下的配置文件加载给定接口或者基类的实现,ServiceLoader会根据给定的类的full name来在META-INF/services下面找对应的文件,在这个文件中定义了所有这个类的子类或者接口的实现类,返回一个实例。

下面以一个具体的例子来说明一下ServiceLoader的具体使用,类似Hadoop FileSystem中的实现。

首先定义一个接口,具体如下:

public interface IService {
	public String sayHello();
	
	public String getScheme();
}

该接口有两个子类,分别为HDFSService和LocalService:

public class HDFSService implements IService {

	@Override
	public String sayHello() {
		return "Hello HDFS!!";
	}

	@Override
	public String getScheme() {
		return "hdfs";
	}
}
public class LocalService implements IService {

	@Override
	public String sayHello() {
		return "Hello Local!!";
	}

	@Override
	public String getScheme() {
		return "local";
	}

}

需要在META-INF/services下以IService这个类的全名来新建立一个文件,文件中的内容为两个实现类的全名,如下:

 org.hadoop.java.HDFSService
 org.hadoop.java.LocalService

所有的实现和配置都已经完成,下面写一个测试类来看一下结果:

public class ServiceLoaderTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//need to define related class full name in /META-INF/services/....
		ServiceLoader<IService> serviceLoader = ServiceLoader
				.load(IService.class);
		for (IService service : serviceLoader) {
			System.out.println(service.getScheme()+"="+service.sayHello());
		}
	}

}
具体的输出来如下:

hdfs=Hello HDFS!!
local=Hello Local!!
可以看到ServiceLoader可以根据IService把定义的两个实现类找出来,返回一个ServiceLoader的实现,而ServiceLoader实现了Iterable接口,所以可以通过ServiceLoader来遍历所有在配置文件中定义的类的实例。Hadoop FileSystem就是通过这个机制来根据不同文件的scheme来返回不同的FileSystem。

FileSystem中的相关实例如下:

  private static void loadFileSystems() {
    synchronized (FileSystem.class) {
      if (!FILE_SYSTEMS_LOADED) {
        ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class);
        for (FileSystem fs : serviceLoader) {
          SERVICE_FILE_SYSTEMS.put(fs.getScheme(), fs.getClass());
        }
        FILE_SYSTEMS_LOADED = true;
      }
    }
  }

FileSystem对应的配置如下:

org.apache.hadoop.fs.LocalFileSystem
org.apache.hadoop.fs.viewfs.ViewFileSystem
org.apache.hadoop.fs.s3.S3FileSystem
org.apache.hadoop.fs.s3native.NativeS3FileSystem
org.apache.hadoop.fs.kfs.KosmosFileSystem
org.apache.hadoop.fs.ftp.FTPFileSystem
org.apache.hadoop.fs.HarFileSystem
通过之前的测试类输出对应的scheme和class如下:

file=class org.apache.hadoop.fs.LocalFileSystem
viewfs=class org.apache.hadoop.fs.viewfs.ViewFileSystem
s3=class org.apache.hadoop.fs.s3.S3FileSystem
s3n=class org.apache.hadoop.fs.s3native.NativeS3FileSystem
kfs=class org.apache.hadoop.fs.kfs.KosmosFileSystem
ftp=class org.apache.hadoop.fs.ftp.FTPFileSystem
har=class org.apache.hadoop.fs.HarFileSystem
hdfs=class org.apache.hadoop.hdfs.DistributedFileSystem
hftp=class org.apache.hadoop.hdfs.HftpFileSystem
hsftp=class org.apache.hadoop.hdfs.HsftpFileSystem
webhdfs=class org.apache.hadoop.hdfs.web.WebHdfsFileSystem

可以看到FileSystem会把所有的FileSystem的实现都以scheme和class来cache,之后就从这个cache中取相应的值。

因此,以后可以通过ServiceLoader来实现一些类似的功能。而不用依赖像Spring这样的第三方框架。

<think>嗯,用户遇到了一个关于Java中io.webtoken.io.Serializer接口实现类找不到的问题。错误信息提到ServiceLoader找不到实现类,可能是因为缺少jjwt-impl.jar。首先,我需要回忆一下JJWT库的结构。JJWT通常分为多个模块,比如jjwt-api、jjwt-impl和jjwt-jackson。jjwt-impl应该包含具体的实现类,而用户可能在依赖中只引入了jjwt-api,没有包含jjwt-impl,导致运行时找不到实现。 然后,检查用户提到的错误信息,ServiceLoader的问题通常和META-INF/services下的配置文件有关。如果依赖配置不正确,或者打包时没有包含这些服务文件,也会导致这个问题。用户可能使用的是Maven或Gradle,所以需要确认依赖是否正确添加。比如,在Maven中,应该同时添加jjwt-api和jjwt-impl的依赖,并且确保版本一致。 另外,用户可能混淆了不同的依赖库。比如,JJWT的不同版本可能有不同的组织ID,比如io.jsonwebtoken和之前的io.webtoken。需要确认用户使用的groupId是否正确。如果用户错误地引用了io.webtoken而不是io.jsonwebtoken,也会导致类找不到的问题。 还有,缓存或构建工具的问题也可能导致依赖没有正确下载。比如,Maven本地仓库可能损坏,或者网络问题导致jjwt-impl.jar没有下载成功。这时候需要清除缓存重新构建。 此外,查看用户提供的引用,他们之前遇到了序列化相关的问题,比如Jackson的配置和Kafka的依赖问题,可能他们在项目中使用了多个库,导致依赖冲突。需要检查是否有版本冲突,排除其他库可能引入的旧版本JJWT。 最后,建议用户检查依赖树,确认jjwt-impl是否存在,版本是否正确,并且打包后的文件是否包含该jar包。如果使用Spring Boot,可能需要确保依赖的作用域正确,比如runtime范围,确保在运行时可用。</think>### 问题分析:`java.io.webtoken.io.Serializer`接口实现类未找到 此问题通常是由于JJWT(Java JWT)库的依赖配置不完整或版本不兼容导致。具体错误提示`ServiceLoader implementation missing`表明框架尝试通过`ServiceLoader`加载`Serializer`接口的实现类,但未找到相关类或配置文件。以下分步骤解决: --- ### 1. **确认依赖配置** JJWT库的模块化设计分为`jjwt-api`(接口定义)和`jjwt-impl`(具体实现)。若缺少`jjwt-impl`模块,将导致实现类无法加载。 **正确配置示例(Maven):** ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.12.5</version> <!-- 使用最新稳定版本 --> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.12.5</version> <scope>runtime</scope> <!-- 确保实现类在运行时生效 --> </dependency> ``` **关键点:** - 需同时添加`jjwt-api`和`jjwt-impl`依赖,且版本必须一致[^3]。 - 若使用Gradle,需在`dependencies`中添加`runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'`。 --- ### 2. **检查依赖冲突** 若项目中其他依赖(如Spring Security、Kafka等)间接引入了旧版本JJWT,可能导致类加载冲突。 **排查方法:** - 执行`mvn dependency:tree`(Maven)或`gradle dependencies`(Gradle)查看依赖树。 - 若发现旧版本JJWT,通过`<exclusions>`排除冲突版本: ```xml <dependency> <groupId>com.example</groupId> <artifactId>conflicting-library</artifactId> <exclusions> <exclusion> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> </exclusion> </exclusions> </dependency> ``` --- ### 3. **验证打包配置** 确保构建工具(如Maven Shade Plugin或Spring Boot Maven Plugin)正确包含`jjwt-impl`的类文件和服务配置文件。 **检查点:** - 打包后的JAR/WAR中应包含`META-INF/services/io.jsonwebtoken.io.Serializer`文件。 - 若使用ProGuard或混淆工具,需配置保留JJWT相关类。 --- ### 4. **清理本地仓库缓存** 若依赖未正确下载(如网络问题或仓库配置错误),可能导致`jjwt-impl.jar`缺失。 **操作步骤:** - 删除Maven本地仓库中`io/jsonwebtoken/jjwt-impl`目录(路径示例:`~/.m2/repository/io/jsonwebtoken/jjwt-impl/`)。 - 重新执行`mvn clean install`或`gradle build`[^2]。 --- ### 5. **版本兼容性验证** 确认JJWT版本与其他组件(如Spring Security、Jackson)兼容。例如: - JJWT `0.12.x`需JDK 8+,且与Spring Boot 3.x兼容。 - 若使用Jackson序列化,需添加依赖`com.fasterxml.jackson.core:jackson-databind`。 --- ### 总结方案 1. 添加完整的JJWT依赖(含`jjwt-impl`)。 2. 排除冲突依赖版本。 3. 验证打包配置。 4. 清理本地仓库并重建项目。 5. 确保组件版本兼容性。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值