原文出自:http://blog.csdn.net/anxpp/article/details/52295168,转载请注明出处,谢谢!

123

    准备做一个IM,实现服务端的时候,准备将所有消息处理器(MessageHandler)使用责任链设计模式,但是又不希望增加处理器的时候修改责任链的实现。

    这时想到了Spring框架的实现,我们在使用Spring Boot 时,只需要实现一些接口,Spring能自动处理。

    所以就想到通过指定接口和要扫描的包路径来获取所有处理器接口的实现,这样动态添加处理器就不需要修改责任链的实现了。

    具体代码如下:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package com.anxpp.im.config;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.net.URL;  
  6. import java.util.ArrayList;  
  7. import java.util.Collection;  
  8. import java.util.Enumeration;  
  9. import java.util.List;  
  10.   
  11. import com.anxpp.im.server.handler.MessageHandler;  
  12.   
  13. /** 
  14.  * 通过接口获取所有实现 
  15.  * 
  16.  * @author http://anxpp.com/ 时间:2016年8月23日 下午10:16:53 
  17.  */  
  18. @SuppressWarnings("rawtypes")  
  19. public class ClassUtil {  
  20.   
  21.     private Class clazz;  
  22.     private String packagePath;  
  23.   
  24.     public ClassUtil(Class clazz, String packagePath) {  
  25.         this.clazz = clazz;  
  26.         this.packagePath = packagePath;  
  27.     }  
  28.   
  29.     @SuppressWarnings("unchecked")  
  30.     public static void main(String[] args) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {  
  31.         List<Class> handlers = new ClassUtil(MessageHandler.class"com.anxpp.im.server.controller").getAllClassByPackage();  
  32.         for (Class<MessageHandler> handler : handlers) {  
  33.             handler.newInstance().dealMessage();  
  34.         }  
  35.     }  
  36.   
  37.     /** 
  38.      * 通过包名获取所有实现(可以将包名配置到统一配置文件中) 
  39.      *  
  40.      * @param packageName 
  41.      * @return 
  42.      */  
  43.     @SuppressWarnings("unchecked")  
  44.     public List<Class> getAllClassByPackage() {  
  45.         ArrayList<Class> returnClassList = new ArrayList<Class>();  
  46.         try {  
  47.             List<Class> allClass = getClasses(packagePath);  
  48.             // 判断是否是一个接口  
  49.             for (int i = 0; i < allClass.size(); i++) {  
  50.                 if (clazz.isAssignableFrom(allClass.get(i))) {  
  51.                     if (!clazz.equals(allClass.get(i))) {  
  52.                         returnClassList.add(allClass.get(i));  
  53.                     }  
  54.                 }  
  55.             }  
  56.         } catch (Exception e) {  
  57.         }  
  58.         return returnClassList;  
  59.     }  
  60.   
  61.     private List<Class> getClasses(String packageName) throws ClassNotFoundException, IOException {  
  62.         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();  
  63.         String path = packageName.replace(".""/");  
  64.         Enumeration<URL> resources = classLoader.getResources(path);  
  65.         List<File> dirs = new ArrayList<File>();  
  66.         while (resources.hasMoreElements()) {  
  67.             URL resource = resources.nextElement();  
  68.             dirs.add(new File(resource.getFile()));  
  69.         }  
  70.         ArrayList<Class> classes = new ArrayList<Class>();  
  71.         for (File directory : dirs) {  
  72.             classes.addAll((Collection<? extends Class>) findClass(directory, packageName));  
  73.         }  
  74.         return classes;  
  75.     }  
  76.   
  77.     private List<Class> findClass(File directory, String packageName) throws ClassNotFoundException {  
  78.         List<Class> classes = new ArrayList<Class>();  
  79.         if (!directory.exists()) {  
  80.             return classes;  
  81.         }  
  82.         File[] files = directory.listFiles();  
  83.         for (File file : files) {  
  84.             if (file.isDirectory()) {  
  85.                 assert !file.getName().contains(".");  
  86.                 classes.addAll(findClass(file, packageName + "." + file.getName()));  
  87.             } else if (file.getName().endsWith(".class")) {  
  88.                 classes.add((Class) Class.forName(packageName + "." + file.getName().substring(0, file.getName().length() - 6)));  
  89.             }  
  90.         }  
  91.         return classes;  
  92.     }  
  93. }  

 

    处理器接口:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package com.anxpp.im.server.handler;  
  2.   
  3. /** 
  4.  * 客户端消息处理器接口 
  5.  * 
  6.  * @author http://anxpp.com/  时间:2016年8月23日  下午8:18:05 
  7.  */  
  8. public interface MessageHandler {  
  9.     void dealMessage();  
  10. }  

 

    其中一个处理器实现如下:

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package com.anxpp.im.server.controller;  
  2.   
  3. import org.slf4j.Logger;  
  4. import org.slf4j.LoggerFactory;  
  5.   
  6. import com.anxpp.im.server.handler.Handler;  
  7. import com.anxpp.im.server.handler.MessageHandler;  
  8.   
  9. @Handler  
  10. public class LoginHandler implements MessageHandler{  
  11.     private static final Logger log = LoggerFactory.getLogger(LoginHandler.class);  
  12.     @Override  
  13.     public void dealMessage() {  
  14.         log.info("登陆消息");  
  15.     }  
  16.   
  17. }  

    这里只是简单的实现,并没有完全贴出责任链的代码。

    其中的@Handler注解还没用上,本意是判断接口同时判断是否注解为处理器。