在Java 9中,何时使用ServiceLoader类在模块中呢?

1. ServiceLoader类介绍

在Java 6中,引入了一种服务提供者接口(Service Provider Interface, SPI)机制,其核心类为java.util.ServiceLoader。ServiceLoader类的作用是从classpath下的META-INF/services目录下读取配置文件,根据配置文件指定的实现类创建对象,并返回相应的服务接口实现类。

2. 使用ServiceLoader类

2.1 在未使用模块化的Java应用中使用ServiceLoader类

在未使用模块化的Java应用中使用ServiceLoader类非常简单,只需要在classpath下的META-INF/services目录下创建一个文件,文件名为服务接口的全限定类名,文件内容为实现类的全限定类名,即可使用ServiceLoader类动态加载并创建服务接口的实现类。

// 服务接口

public interface MessageService {

void send(String message);

}

// 服务接口实现类1

public class EmailMessageServiceImpl implements MessageService {

@Override

public void send(String message) {

System.out.println("通过邮件发送消息:" + message);

}

}

// 服务接口实现类2

public class SmsMessageServiceImpl implements MessageService {

@Override

public void send(String message) {

System.out.println("通过短信发送消息:" + message);

}

}

// 配置文件

// 在classpath下的META-INF/services目录下创建文件:com.example.MessageService

// 文件内容为实现类的全限定类名,如下所示:

com.example.EmailMessageServiceImpl

com.example.SmsMessageServiceImpl

// 加载服务接口的实现类

ServiceLoader<MessageService> messageServices = ServiceLoader.load(MessageService.class);

for (MessageService messageService : messageServices) {

messageService.send("hello world");

}

// 执行结果为:

// 通过邮件发送消息:hello world

// 通过短信发送消息:hello world

2.2 在模块中使用ServiceLoader类

在Java 9中,引入了模块化机制,模块化使得Java应用更具可维护性、可重用性、可伸缩性等方面的优势。在模块化的Java应用中,可以在module-info.java文件中使用requires和provides关键字来声明服务接口和服务实现类。

2.2.1 声明服务接口

在module-info.java文件中使用requires关键字声明服务接口模块,如下所示:

module com.example.message {

exports com.example.message;

requires java.base;

}

上面的代码声明了com.example.message模块,该模块导出com.example.message包,同时依赖于java.base模块。

2.2.2 声明服务接口实现类

在module-info.java文件中使用provides和with关键字声明服务接口实现类,如下所示:

module com.example.sms {

requires com.example.message;

provides com.example.message.MessageService

with com.example.sms.SmsMessageServiceImpl;

}

module com.example.email {

requires com.example.message;

provides com.example.message.MessageService

with com.example.email.EmailMessageServiceImpl;

}

上面的代码声明了com.example.sms和com.example.email两个模块,这两个模块都依赖于com.example.message模块,同时使用provides和with关键字声明了提供服务的服务接口实现类。

2.2.3 使用ServiceLoader类获取服务接口实现类

在模块化的Java应用中,可以使用ServiceLoader类来获取服务接口的实现类,如下所示:

ServiceLoader<MessageService> messageServices = ServiceLoader.load(ModuleLayer.boot(), MessageService.class);

for (MessageService messageService : messageServices) {

messageService.send("hello world");

}

上面的代码使用ServiceLoader.load()方法获取服务接口的实现类,使用ModuleLayer.boot()方法获取引导层模块,使得ServiceLoader类可以加载来自引导层和应用层的服务接口实现类。

3. 小结

ServiceLoader类是Java中的一种全新的机制,它可以更方便、更灵活地实现模块之间的解耦和扩展。在未使用模块化的Java应用中,ServiceLoader类的使用非常简单,只需要在classpath下的META-INF/services目录下创建一个文件即可。在模块化的Java应用中,使用ServiceLoader类获取服务接口实现类需要在module-info.java文件中使用provides和with关键字声明服务接口实现类。

后端开发标签