2. ServiceLoader
Java 开发人员经常希望将使用和创建组件的内容区分开来。这通常是通过创建一个描述组件动作的接口,并使用某种中介创建组件实例来完成的。很多开发人员使用 Spring 框架来完成,但还有其他的方法,它比 Spring 容器更轻量级。
java.util 的 ServiceLoader 类能读取隐藏在 JAR 文件中的配置文件,并找到接口的实现,然后使这些实现成为可选择的列表。例如,如果您需要一个私仆(personal-servant)组件来完成任务,您可以使用清单 2 中的代码来实现:
清单 2. IPersonalServant
public interface IPersonalServant
{
// Process a file of commands to the servant
public void process(java.io.File f)
throws java.io.IOException;
public boolean can(String command);
}
{
// Process a file of commands to the servant
public void process(java.io.File f)
throws java.io.IOException;
public boolean can(String command);
}
can() 方法可让您确定所提供的私仆实现是否满足需求。清单 3 中的 ServiceLoader 的 IPersonalServant 列表基本上满足需求:
清单 3. IPersonalServant 行吗?
import java.io.*;
import java.util.*;
public class Servant
{
public static void main(String[] args)
throws IOException
{
ServiceLoader<IPersonalServant> servantLoader =
ServiceLoader.load(IPersonalServant.class);
IPersonalServant i = null;
for (IPersonalServant ii : servantLoader)
if (ii.can("fetch tea"))
i = ii;
if (i == null)
throw new IllegalArgumentException("No suitable servant found");
for (String arg : args)
{
i.process(new File(arg));
}
}
}
import java.util.*;
public class Servant
{
public static void main(String[] args)
throws IOException
{
ServiceLoader<IPersonalServant> servantLoader =
ServiceLoader.load(IPersonalServant.class);
IPersonalServant i = null;
for (IPersonalServant ii : servantLoader)
if (ii.can("fetch tea"))
i = ii;
if (i == null)
throw new IllegalArgumentException("No suitable servant found");
for (String arg : args)
{
i.process(new File(arg));
}
}
}
假设有此接口的实现,如清单 4: