今天闲着没事儿,研究了一把Apache Commons Discovery包,发现还不错,跟大家分享一下。
Discovery组件被用以查找可插拔接口的实现实例,它提供了一种通用的实例化这些实现的方式,而且可以管理单例(工厂)的生命周期。本质上来讲,就是定位那些实现了给定Java接口的类,并实例化。除此之外,Discovery还可以用以在给定的classpath中查找并加载资源文件。
Discovery组件在查找所有的实现类的时候需要预先将允许被查找的实现类配置到默认的配置文件中,默认的配置文件为:
/META-INF/services/<YOUR Interface whole name including pkg name>, Discovery将依次加载该文件中配置的允许加载的实现类。
下面将举例说明:
首先定义一个Interface:Action
package com.javaeye.terrencexu.discovery;
public interface Action {
public String getName();
}
然后在不同的包里分别实现Action接口,如下(请注意包名)
package com.javaeye.terrencexu.discovery.impl;
import com.javaeye.terrencexu.discovery.Action;
public class CreateAction implements Action {
@Override
public String getName() {
return "Create Action";
}
}
package com.javaeye.terrencexu.discovery.impl;
import com.javaeye.terrencexu.discovery.Action;
public class DeleteAction implements Action {
@Override
public String getName() {
return "Delete Action";
}
}
package com.javaeye.terrencexu.discovery.impl2;
import com.javaeye.terrencexu.discovery.Action;
public class AddAction implements Action {
@Override
public String getName() {
return "Add Action";
}
}
package com.javaeye.terrencexu.discovery.impl2;
import com.javaeye.terrencexu.discovery.Action;
public class RemoveAction implements Action {
@Override
public String getName() {
return "Remove Action";
}
}
接下来将定义配置文件,按序定义允许被加载的实现类,该文件默认存在位置为/META-INF/services/,文件名为com.javaeye.terrencexu.discovery.Action,文件内容如下:
# Display in order
com.javaeye.terrencexu.discovery.impl.CreateAction
com.javaeye.terrencexu.discovery.impl.DeleteAction
com.javaeye.terrencexu.discovery.impl2.AddAction
这样所有的准备材料就都已经齐全了,接下来可以验证一把了,如下:
/**
* CreateAction/DeleteAction/AddAction have been defined in /META-INF/services/com.javaeye.terrencexu.discovery.Action
*
* And the order is CreateAction > DeleteAction > AddAction
*/
@SuppressWarnings("unchecked")
public void testGetAllProviders() {
String[] expectedResults = new String[] {"Create Action", "Delete Action", "Add Action"};
Enumeration<Action> enu = Service.providers(Action.class);
int count = 0;
while (enu.hasMoreElements()) {
Action action = enu.nextElement();
assertTrue("The action name should be \"" + expectedResults[count] + "\", but actually is \"" + action.getName() + "\"",
action.getName().equals(expectedResults[count]));
count ++;
}
assertEquals(count, expectedResults.length);
}
可以发现,因为RemoveAction没有被配置到service文件中,所以将不会被加载,另外一点儿就是,配置文件中的定义顺序即加载顺序。
除此之外,Discovery提供了singleton模式加载唯一实现,并且该实现将被缓存在cache中,除非通过显示的调用release()方法释放缓存,否则所有之后的调用,都将返回初次调用加载的Action。
public void testFindCreateAction() {
try {
// Load provider com.javaeye.terrencexu.discovery.impl.CreateAction
Action createAction = (Action) DiscoverSingleton.find(Action.class, CreateAction.class.getName());
assertEquals("Create Action", createAction.getName());
} finally {
DiscoverSingleton.release();
}
}
还有一点需要说明的是,如果定义了默认的service文件,无论通过singleton模式加载的实现类有没有被配置在service文件中,都将默认加载配置中文中的第一个Action,比如上文中的CreateAction。
public void testFindDeleteActionInConfig() {
try {
// Load provider com.javaeye.terrencexu.discovery.impl.CreateAction
Action deleteAction = (Action) DiscoverSingleton.find(Action.class, DeleteAction.class.getName());
// As the default configuration file defines the CreateAction as the first element, so you will always get the CreateAction as singleton.
assertEquals("Create Action", deleteAction.getName());
} finally {
DiscoverSingleton.release();
}
}
那么如果必须使用service文件,又想通过singleton模式加载某特定的实现类该怎么办呢?可以通过传递Properties到DiscoverSingleton中去改变它的行为,如下:
public void testFindDeleteActionWithProperty() {
try {
Properties props = new Properties();
props.setProperty(Action.class.getName(), DeleteAction.class.getName());
// Load provider com.javaeye.terrencexu.discovery.impl.CreateAction
Action deleteAction = (Action) DiscoverSingleton.find(Action.class, props);
assertEquals("Delete Action", deleteAction.getName());
} finally {
DiscoverSingleton.release();
}
}
除了加载类之外,很多情况下我们还想加载资源文件,比如在你的classpath下有一个配置文件为/conf/testResource,下面我们通过Discovery去加载该资源文件:
public void testFindResources() {
ClassLoaders loaders = new ClassLoaders();
ClassLoader cl = getClass().getClassLoader();
if(cl != null) {
loaders.put(getClass().getClassLoader(), true);
} else {
loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), true);
}
String name = "conf/testResource";
DiscoverResources discovery = new DiscoverResources(loaders);
ResourceIterator iter = discovery.findResources(name);
while(iter.hasNext()) {
Resource resource = iter.nextResource();
URL url = resource.getResource();
System.out.println(url);
}
}
Discovery还有其他一些功能这里就不在详细的一一赘述了,可以参考http://commons.apache.org/discovery/index.html进一步详细了解。
下图是我的例子的目录结构,仅供参考:
然后附件中有source code,仅供参考。
- 大小: 12.3 KB
分享到:
相关推荐
2. **PX(Plug'n'X)机制**:这是Apache Commons Discovery的一个重要特性,允许在不预先知道具体实现的情况下,动态地插拔组件。 PX机制基于Jini技术,使得服务提供者和服务消费者可以在运行时动态交互。 3. **...
Apache Commons ID 和 Commons Discovery 是两个在Java开发中广泛使用的开源库,它们是Apache软件基金会的项目,为开发者提供了丰富的工具和功能。 Apache Commons ID 主要关注于生成唯一标识(ID)的功能,它提供...
2. `Service` 接口:表示一个可发现的服务,实现了该接口的类可以被Apache Commons Discovery找到。 3. `PropertiesUtils` 类:用于处理与属性相关的操作,如查找具有特定值的属性。 4. `XMLUtils` 类:处理XML文档...
1. **服务发现**:Apache Commons Discovery提供了一种方法来查找符合特定接口或类的实现。这在模块化系统中特别有用,因为系统组件可以动态地找到并使用其他组件,而无需硬编码依赖关系。 2. **Java SPI支持**:它...
Apache Commons Discovery的核心功能在于提供了一种机制,使得Java应用程序能够自动查找和使用运行时环境中的服务。它支持的服务发现机制包括了JNDI(Java Naming and Directory Interface)查询、类路径扫描、XML...
Apache Commons 是一个由 Apache 软件基金会维护...通过合理地使用 Apache Commons,开发者可以更加专注于业务逻辑,而不是基础的工具实现。在实际项目中,选择合适的 Commons 组件可以有效地提升开发效率和代码质量。
总之,Apache Commons Discovery提供了一套全面的解决方案,帮助Java开发者在运行时实现服务的动态发现和使用,从而增强了应用的灵活性和可扩展性。通过深入了解和合理使用这个库,我们可以构建更加健壮、易于维护的...
commons-discovery-0.2.jar
* 指定日志器:在属性文件 common-logging.properties 中设置实现接口的类。例如,设置 Log4j 为所使用的日志包。 org.apache.commons.logging.Log 接口中定义的方法,按严重性由高到低的顺序有: * log.fatal...
Apache Commons Math3提供的`PolynomialCurveFitter`类实现了这一功能。该类允许我们根据给定的数据点拟合一个多项式曲线,以求得最佳拟合多项式的系数。 使用`PolynomialCurveFitter`的第一步是准备数据。我们需要...
2. Apache Commons CLI: 命令行接口(CLI)工具包简化了命令行参数解析。它可以自动处理短选项、长选项、选项组合以及帮助信息的生成,让编写命令行程序变得更加简单。 3. Apache Commons Codec: 这个库提供了各种...
Apache Commons是Java开发中不可或缺的一部分,它提供了一系列实用的工具类和组件,极大地丰富了Java标准库的功能。这个工具集包含了许多模块,每个模块都专注于特定的编程任务,旨在简化和优化开发流程。以下是一些...
Discovery组件被用以查找可插拔接口的实现实例,它提供了一种通用的实例化这些实现的方式,而且可以管理单例(工厂)的生命周期。本质上来讲,就是定位那些实现了给定Java接口的类,并实例化。除此之外,Discovery还...
commons-lang3.3.1.jar、Apache Commons包中的一个,包含了一些数据类型工具类,是java.lang.*的扩展。必须使用的jar包。为JRE5.0+的更好的版本所提供 Jar文件包含的类: META-INF/MANIFEST.MFMETA-INF/LICENSE....
apache commons all 中文api合集
commons-lang3.3.1.jar、Apache Commons包中的一个,包含了一些数据类型工具类,是java.lang.*的扩展。必须使用的jar包。为JRE5.0+的更好的版本所提供 Jar文件包含的类: META-INF/MANIFEST.MFMETA-INF/LICENSE....
在JavaMail中,配置和使用邮件服务可能相对复杂,而Apache Commons Mail则通过提供预定义的邮件实现和简单易用的接口来解决了这个问题。 **Apache Commons Mail基本概念** 1. **邮件组件**:Apache Commons Mail ...
在Web开发中,Apache Commons 的组件被广泛使用,尤其是在 JSP+Servlet 的学习,以及基于 Spring(SSM)、Struts(SSH)等框架的应用开发中。 Apache Commons 中包含多个模块,每个模块都专注于特定的功能领域,...