疯狂

STANDING ON THE SHOULDERS OF GIANTS
posts - 481, comments - 486, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

apache discovery

Posted on 2010-09-04 11:34 疯狂 阅读(661) 评论(0)  编辑  收藏 所属分类: java apache项目

转载:http://terrencexu.javaeye.com/blog/715982

Discovery组件被用以查找可插拔接口的实现实例,它提供了一种通用的实例化这些实现的方式,而且可以管理单例(工厂)的生命周期。本质上来讲,就是定位那些实现了给定Java接口的类,并实例化。除此之外,Discovery还可以用以在给定的classpath中查找并加载资源文件。

 

Discovery组件在查找所有的实现类的时候需要预先将允许被查找的实现类配置到默认的配置文件中,默认的配置文件为:

/META-INF/services/<YOUR Interface whole name including pkg name>, Discovery将依次加载该文件中配置的允许加载的实现类。

 

下面将举例说明:

首先定义一个Interface:Action

Java代码 复制代码
  1. package com.javaeye.terrencexu.discovery;   
  2.   
  3. public interface Action {   
  4.   
  5.     public String getName();   
  6.        
  7. }  

 

然后在不同的包里分别实现Action接口,如下(请注意包名)

Java代码 复制代码
  1. package com.javaeye.terrencexu.discovery.impl;   
  2.   
  3. import com.javaeye.terrencexu.discovery.Action;   
  4.   
  5. public class CreateAction implements Action {   
  6.   
  7.     @Override  
  8.     public String getName() {   
  9.         return "Create Action";   
  10.     }   
  11.   
  12. }  

 

Java代码 复制代码
  1. package com.javaeye.terrencexu.discovery.impl;   
  2.   
  3. import com.javaeye.terrencexu.discovery.Action;   
  4.   
  5. public class DeleteAction implements Action {   
  6.   
  7.     @Override  
  8.     public String getName() {   
  9.         return "Delete Action";   
  10.     }   
  11.   
  12. }  

 

Java代码 复制代码
  1. package com.javaeye.terrencexu.discovery.impl2;   
  2.   
  3. import com.javaeye.terrencexu.discovery.Action;   
  4.   
  5. public class AddAction implements Action {   
  6.   
  7.     @Override  
  8.     public String getName() {   
  9.         return "Add Action";   
  10.     }   
  11.   
  12. }  

 

Java代码 复制代码
  1. package com.javaeye.terrencexu.discovery.impl2;   
  2.   
  3. import com.javaeye.terrencexu.discovery.Action;   
  4.   
  5. public class RemoveAction implements Action {   
  6.   
  7.     @Override  
  8.     public String getName() {   
  9.         return "Remove Action";   
  10.     }   
  11.   
  12. }  

 

接下来将定义配置文件,按序定义允许被加载的实现类,该文件默认存在位置为/META-INF/services/,文件名为com.javaeye.terrencexu.discovery.Action,文件内容如下:

Java代码 复制代码
  1. # Display in order   
  2.   
  3. com.javaeye.terrencexu.discovery.impl.CreateAction   
  4. com.javaeye.terrencexu.discovery.impl.DeleteAction   
  5. com.javaeye.terrencexu.discovery.impl2.AddAction  

 

这样所有的准备材料就都已经齐全了,接下来可以验证一把了,如下:

Java代码 复制代码
  1.  /**  
  2.  *  CreateAction/DeleteAction/AddAction have been defined in /META-INF/services/com.javaeye.terrencexu.discovery.Action  
  3.  *    
  4.  *  And the order is CreateAction > DeleteAction > AddAction  
  5.  */  
  6. @SuppressWarnings("unchecked")   
  7. public void testGetAllProviders() {   
  8.     String[] expectedResults = new String[] {"Create Action""Delete Action""Add Action"};   
  9.            
  10.     Enumeration<Action> enu = Service.providers(Action.class);   
  11.   
  12.     int count = 0;   
  13.     while (enu.hasMoreElements()) {   
  14.         Action action = enu.nextElement();   
  15.         assertTrue("The action name should be \"" + expectedResults[count] + "\", but actually is \"" + action.getName() + "\"",    
  16.                action.getName().equals(expectedResults[count]));   
  17.         count ++;   
  18.     }   
  19.            
  20.     assertEquals(count, expectedResults.length);   
  21. }  

 

可以发现,因为RemoveAction没有被配置到service文件中,所以将不会被加载,另外一点儿就是,配置文件中的定义顺序即加载顺序。

 

除此之外,Discovery提供了singleton模式加载唯一实现,并且该实现将被缓存在cache中,除非通过显示的调用release()方法释放缓存,否则所有之后的调用,都将返回初次调用加载的Action。

Java代码 复制代码
  1. public void testFindCreateAction() {   
  2.     try {   
  3.         // Load provider com.javaeye.terrencexu.discovery.impl.CreateAction   
  4.         Action createAction = (Action) DiscoverSingleton.find(Action.class, CreateAction.class.getName());   
  5.         assertEquals("Create Action", createAction.getName());   
  6.     } finally {   
  7.         DiscoverSingleton.release();   
  8.     }   
  9. }  

 

 

还有一点需要说明的是,如果定义了默认的service文件,无论通过singleton模式加载的实现类有没有被配置在service文件中,都将默认加载配置中文中的第一个Action,比如上文中的CreateAction。

Java代码 复制代码
  1. public void testFindDeleteActionInConfig() {   
  2.     try {   
  3.         // Load provider com.javaeye.terrencexu.discovery.impl.CreateAction   
  4.         Action deleteAction = (Action) DiscoverSingleton.find(Action.class, DeleteAction.class.getName());   
  5.            
  6.         // As the default configuration file defines the CreateAction as the first element, so you will always get the CreateAction as singleton.    
  7.         assertEquals("Create Action", deleteAction.getName());   
  8.     } finally {   
  9.         DiscoverSingleton.release();   
  10.     }   
  11. }  

 

那么如果必须使用service文件,又想通过singleton模式加载某特定的实现类该怎么办呢?可以通过传递Properties到DiscoverSingleton中去改变它的行为,如下:

Java代码 复制代码
  1. public void testFindDeleteActionWithProperty() {   
  2.     try {   
  3.         Properties props = new Properties();   
  4.         props.setProperty(Action.class.getName(), DeleteAction.class.getName());   
  5.            
  6.         // Load provider com.javaeye.terrencexu.discovery.impl.CreateAction   
  7.         Action deleteAction = (Action) DiscoverSingleton.find(Action.class, props);   
  8.         assertEquals("Delete Action", deleteAction.getName());   
  9.     } finally {   
  10.         DiscoverSingleton.release();   
  11.     }   
  12. }  

 

除了加载类之外,很多情况下我们还想加载资源文件,比如在你的classpath下有一个配置文件为/conf/testResource,下面我们通过Discovery去加载该资源文件:

Java代码 复制代码
  1. public void testFindResources() {   
  2.     ClassLoaders loaders = new ClassLoaders();   
  3.     ClassLoader cl = getClass().getClassLoader();   
  4.     if(cl != null) {   
  5.         loaders.put(getClass().getClassLoader(), true);   
  6.     } else {   
  7.         loaders.put(JDKHooks.getJDKHooks().getSystemClassLoader(), true);   
  8.     }   
  9.        
  10.     String name = "conf/testResource";   
  11.     DiscoverResources discovery = new DiscoverResources(loaders);   
  12.     ResourceIterator iter = discovery.findResources(name);   
  13.        
  14.     while(iter.hasNext()) {   
  15.         Resource resource = iter.nextResource();   
  16.         URL url = resource.getResource();   
  17.         System.out.println(url);   
  18.     }   
  19. }  

 

Discovery还有其他一些功能这里就不在详细的一一赘述了,可以参考http://commons.apache.org/discovery/index.html进一步详细了解。

 

下图是我的例子的目录结构,仅供参考:


然后附件中有source code,仅供参考。


 


只有注册用户登录后才能发表评论。


网站导航: