使用Apache Commons 的 Discovery 工具包可以实现接口和实现的分离,包括JAR SPI规范的简单实现。结合面向接口的编程方法,可以实现一个简单的面向服务的调用方式。
//
初始化
ClassLoaders loaders
=
ClassLoaders.getAppLoaders(serviceClass, serviceClass.getClass(),
false
);
DiscoverClass discover
=
new
DiscoverClass(loaders);
//
使用newInstance方式直接产生接口实现的实例
implInstance
=
(PublicService) discover.newInstance(serviceClass, defaultImpl);
//
也可以使用find的方式返回对应的实现类
implClass
=
discover.find(serviceClass, configFile, defaultImpl);
上面的用法中,接口和实现类的映射关系在一个properties配置文件中定义,格式是:
XXXable
=
XXXimpl
也可以在classpath中的jar的META-INF/services中定义,格式是:
META
-
INF
/
services
/
xxxable(文件) 文件内容为 xxximpl
以下事完整程序中使用了cglib的 net.sf.cglib.proxy.Enhancer 对返回的实现类进行了增强,可以实现一个简单的面向方面的程序结构:
代码示例
public
class
ServiceFinder {
private
static
final
String configFile
=
"
services.properties
"
;
private
static
Enhancer enhancer
=
new
Enhancer();
private
ServiceFinder() {
}
public
static
PublicService lookup(Class serviceClass) {
return
lookup(serviceClass,
null
);
}
public
static
PublicService lookup(Class serviceClass, String defaultImpl) {
//
创建一个类装入器的实例
ClassLoaders loaders
=
ClassLoaders.getAppLoaders(serviceClass, serviceClass.getClass(),
false
);
DiscoverClass discover
=
new
DiscoverClass(loaders);
PublicService impl
=
null
;
try
{
Class implClass
=
null
;
//
用DiscoverClass的实例来查找实现类
if
(defaultImpl
==
null
||
""
.equals(defaultImpl)) {
implClass
=
discover.find(serviceClass, PropertiyFile.load(configFile));
}
else
{
implClass
=
discover.find(serviceClass, configFile, defaultImpl);
}
enhancer.setSuperclass(implClass);
enhancer.setCallback(
new
ServiceInterceptor(implClass.toString()));
impl
=
(PublicService) enhancer.create();
//
using DiscoverClass instance lookup the impelement
//
impl = (PublicService) discover.newInstance(serviceClass, defaultImpl);
}
catch
(Exception ex) {
ex.printStackTrace();
throw
new
IllegalArgumentException(
"
无法获取指定的服务项
"
);
}
return
impl;
}
Technorati : Apache Discovery