大多数应用中我们使用依赖注入让代码保持松耦合,但有时我们仅需要简单DI,而不是其他较重的框架,如Spring ,Google Guice 等,它们会让jar包非常大,增加了很多不必要的类。Java 自身也提供了 ServiceLoader 类 ,用于运行时注入依赖。
ServiceLoader 自JDK 3引入仅作内部使用,到JDK6,该类范围为public,但仍然是final类 —— 我们不能扩展其功能。ServiceLoader 在 JDK 9 中扮演重要角色。本文通过示例给你展示如何使用 ServiceLoader 。
示例
需要 JDK >= 6 , 使用maven 进行打包项目生成jar文件。
定义服务抽象接口
创建服务的抽象层:
package com.dataz.service;
public interface GreetingsService {
/**
* greeting to name
* @param name name
*/
void sayHello(String name);
}
我们定义两个服务实现类:
package com.dataz.service.impl;
import com.dataz.service.GreetingsService;
public class ConsoleGreetings implements GreetingsService {
@Override
public void sayHello(String name) {
System.out.println("Hello to " + name + " on console.");
}
}
package com.dataz.service.impl;
import com.dataz.service.GreetingsService;
public class EmailGreetings implements GreetingsService {
@Override
public void sayHello(String name) {
System.out.println("Hello to " + name + " by email.");
}
}
定义 Provider
现在我们需要定义提供者,其负责在运行时载入服务实现并创建相应实例。
package com.dataz.provider;
import com.dataz.service.GreetingsService;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
public class GreetingsProvider {
private static GreetingsProvider provider;
private ServiceLoader<GreetingsService> loader;
private GreetingsProvider() {
loader = ServiceLoader.load(GreetingsService.class);
}
public static GreetingsProvider getInstance() {
if(provider == null) {
provider = new GreetingsProvider();
}
return provider;
}
public void greeting(String greetingType, String name){
loader.iterator().forEachRemaining(s -> {
if (s.getClass().getName().contains(greetingType)){
s.sayHello(name);
}
});
}
public GreetingsService serviceImpl() {
GreetingsService service = loader.iterator().next();
if(service != null) {
return service;
} else {
throw new NoSuchElementException("No implementation for GreetingsProvider");
}
}
}
同时定义了两个方法用于测试,greeting 方法根据名称判断调用那个实现,serviceImpl 仅返回一个具体实现。实际应用中可根据业务实现更有意义的逻辑,这里仅为演示。
创建目录
在 resources
目录下(类路径) 创建目录 META-INF/services
,并在该目录下创建文件 com.dataz.service.GreetingsService
,该文件名正是服务接口的全路径名称。文件内容包括所有的实现类:
com.dataz.service.impl.ConsoleGreetings
com.dataz.service.impl.EmailGreetings
测试
package com.dataz.main;
import com.dataz.provider.GreetingsProvider;
import com.dataz.service.GreetingsService;
public class Launcher {
public static void main(String... args) {
try{
GreetingsProvider provider = GreetingsProvider.getInstance();
GreetingsService service = provider.serviceImpl();
service.sayHello("tom");
provider.greeting("Email", "jack");
}catch (Exception e){
e.printStackTrace();
}
}
}
输出内容:
Hello to tom on console.
Hello to jack by email.
输出与期望一致,provider成功加载并创建了对于实例。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/118339081