获取指定包名下所有的类

来源:互联网 发布:江湖笑歌词.知乎 编辑:程序博客网 时间:2024/05/04 01:12
我们需要开发一个类加载器,来加载该基础包名下的所有类,比如使用了某注解的类,或实现了某接口的类,在或者继承了某父类的所有子类。

       下一个ClassUtil工具类作为类加载器,提供与类相关的方法,比如获取类加载器,加载类,获取指定包下的所有类。ClassUtil的代码如下:

[java] view plain copy print?
  1. package org.smart4j.framework.org.smart4j.framework.util;  
  2.   
  3. import org.apache.commons.lang3.StringUtils;  
  4. import org.slf4j.Logger;  
  5. import org.slf4j.LoggerFactory;  
  6.   
  7. import java.io.File;  
  8. import java.io.FileFilter;  
  9. import java.net.JarURLConnection;  
  10. import java.net.URL;  
  11. import java.util.Enumeration;  
  12. import java.util.HashSet;  
  13. import java.util.Set;  
  14. import java.util.jar.JarEntry;  
  15. import java.util.jar.JarFile;  
  16.   
  17. /** 
  18.  * Created by jack on 2017/5/22. 
  19.  * 类操作工具类 
  20.  */  
  21. public final class ClassUtil {  
  22.     private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);  
  23.   
  24.     /** 
  25.      * 获取类加载器 
  26.      * 获取加载器类的实现比较简单,只需获取当前线程的ClassLoader 
  27.      */  
  28.     public static ClassLoader getClassLoader() {  
  29.         return Thread.currentThread().getContextClassLoader();  
  30.     }  
  31.   
  32.     /** 
  33.      * 加载类 
  34.      * 加载类需要提供类名与是否初始化的标志,这里提到的初始化指是否执行类的静态代码块; 
  35.      * 为了提高加载类的性能,可以将loadClass方法的isInitialized参数设置false 
  36.      */  
  37.     public static Class<?> loadClass(String className, boolean isInitialized) {  
  38.         Class<?> cls = null;  
  39.         try {  
  40.             //进行类加载  
  41.             cls = Class.forName(className, isInitialized, getClassLoader());  
  42.         } catch (ClassNotFoundException e) {  
  43.             LOGGER.error("load class failure.", e);  
  44.             throw new RuntimeException(e);  
  45.         }  
  46.         return cls;  
  47.     }  
  48.   
  49.     /** 
  50.      * 获取指定包名下所有的类; 
  51.      * 获取指定包名下所有的类,需要根据包名并将其转换为文件路径,读取class文件或jar包,获取指定的类名去加载类 
  52.      */  
  53.     public static Set<Class<?>> getClassSet(String packageName) {  
  54.         Set<Class<?>> classSet = new HashSet<Class<?>>();  
  55.         try {  
  56.             Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".""/"));  
  57.             while (urls.hasMoreElements()) {  
  58.                 URL url = urls.nextElement();  
  59.                 if (url != null) {  
  60.                     String protocol = url.getProtocol();  
  61.                     if ("file".equals(protocol)) {  
  62.                         String packagePath = url.getPath().replace("%20""");  
  63.                         addClass(classSet, packagePath, packageName);  
  64.                     } else if ("jar".equals(protocol)) {  
  65.                         JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();  
  66.                         if (jarURLConnection != null) {  
  67.                             JarFile jarFile = jarURLConnection.getJarFile();  
  68.                             if (jarFile != null) {  
  69.                                 Enumeration<JarEntry> jarEntries = jarFile.entries();  
  70.                                 while (jarEntries.hasMoreElements()) {  
  71.                                     JarEntry jarEntry = jarEntries.nextElement();  
  72.                                     String jarEntryName = jarEntry.getName();  
  73.                                     if (jarEntryName.endsWith(".class")) {  
  74.                                         String className = jarEntryName.substring(0, jarEntryName.lastIndexOf("."))  
  75.                                                 .replaceAll("/"".");  
  76.                                         doAddClass(classSet, className);  
  77.                                     }  
  78.                                 }  
  79.                             }  
  80.                         }  
  81.                     }  
  82.                 }  
  83.             }  
  84.         } catch (Exception e) {  
  85.             LOGGER.error("get class set failure.", e);  
  86.             throw new RuntimeException(e);  
  87.         }  
  88.         return classSet;  
  89.     }  
  90.   
  91.     private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {  
  92.         File[] files = new File(packagePath).listFiles(new FileFilter() {  
  93.             public boolean accept(File file) {  
  94.                 return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();  
  95.             }  
  96.         });  
  97.         for (File file : files) {  
  98.             String fileName = file.getName();  
  99.             if (file.isFile()) {  
  100.                 String className = fileName.substring(0, fileName.lastIndexOf("."));  
  101.                 if (StringUtils.isNotEmpty(packageName)) {  
  102.                     className = packageName + "." + className;  
  103.                 }  
  104.                 doAddClass(classSet, className);  
  105.             } else {  
  106.                 String subPackagePath = fileName;  
  107.                 if (StringUtils.isNotEmpty(packageName)){  
  108.                     subPackagePath = packagePath +"/"+subPackagePath;  
  109.                 }  
  110.                 String subPackageName = fileName;  
  111.                 if (StringUtils.isNotEmpty(packageName)){  
  112.                     subPackageName = packageName +"."+subPackageName;  
  113.                 }  
  114.                 addClass(classSet,subPackagePath,subPackageName);  
  115.             }  
  116.         }  
  117.     }  
  118.   
  119.     private static void doAddClass(Set<Class<?>> classSet, String className) {  
  120.         Class<?> cls = loadClass(className, false);  
  121.         classSet.add(cls);  
  122.     }  
  123. }  


       我们的目标是在控制器类上使用Controller注解,在控制器类的方法上使用Action注解,在服务类上使用Service注解,在控制器类中可以使用Inject注解将服务依赖注入进来。因此我们需要自定义4个注解类。

       控制器类注解代码如下:

[java] view plain copy print?
  1. package org.smart4j.framework.annotation;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Retention;  
  5. import java.lang.annotation.RetentionPolicy;  
  6. import java.lang.annotation.Target;  
  7.   
  8. /** 
  9.  * Created by jack on 2017/5/22. 
  10.  * 控制器注解 
  11.  */  
  12. @Target(ElementType.TYPE)  
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. public @interface Controller {  
  15. }  

      Action方法注解代码如下:

[java] view plain copy print?
  1. package org.smart4j.framework.annotation;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Retention;  
  5. import java.lang.annotation.RetentionPolicy;  
  6. import java.lang.annotation.Target;  
  7.   
  8. /** 
  9.  * Created by jack on 2017/5/22. 
  10.  * Action 方法注解 
  11.  */  
  12. @Target(ElementType.METHOD)  
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. public @interface Action {  
  15.     /** 
  16.      * 请求路径 
  17.      */  
  18.     String value();  
  19. }  


     服务类注解代码如下:

[java] view plain copy print?
  1. package org.smart4j.framework.annotation;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Retention;  
  5. import java.lang.annotation.RetentionPolicy;  
  6. import java.lang.annotation.Target;  
  7.   
  8. /** 
  9.  * Created by jack on 2017/5/22. 
  10.  * 服务类注解 
  11.  */  
  12. @Target(ElementType.TYPE)  
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. public @interface Service {  
  15. }  


      依赖注解代码如下:

[java] view plain copy print?
  1. package org.smart4j.framework.annotation;  
  2.   
  3. import java.lang.annotation.ElementType;  
  4. import java.lang.annotation.Retention;  
  5. import java.lang.annotation.RetentionPolicy;  
  6. import java.lang.annotation.Target;  
  7.   
  8. /** 
  9.  * Created by jack on 2017/5/22. 
  10.  * 依赖注解类 
  11.  */  
  12. @Target(ElementType.FIELD)  
  13. @Retention(RetentionPolicy.RUNTIME)  
  14. public @interface Inject {  
  15. }  



    由于我们在smart.properties配置文件中指定了

smart.framework.app.base_package

   他是整个应用的基础包名,所以我们有必要提供一个ClassHelper助手类,让它分别获取应用包名下的所有的类,应用包名下所有的Service类,应用包名下所有的Controller类。此外可以将带有Controller注解和Service注解的类所产生的对象理解为smart框架所管理的bean,所以有必要在ClassHelper类中增加一个获取应用包名下所有bean类的方法,ClassHelper类的代码如下:

     

[java] view plain copy print?
  1. package org.smart4j.framework.helper;  
  2.   
  3. import org.smart4j.framework.annotation.Controller;  
  4. import org.smart4j.framework.annotation.Service;  
  5. import org.smart4j.framework.org.smart4j.framework.util.ClassUtil;  
  6.   
  7. import java.util.HashSet;  
  8. import java.util.Set;  
  9.   
  10. /** 
  11.  * Created by jack on 2017/5/22. 
  12.  * 类操作助手类 
  13.  */  
  14. public class ClassHelper {  
  15.     /** 
  16.      * 定义类集合,用于存放所加载的类 
  17.      */  
  18.     private static final Set<Class<?>> CLASS_SET;  
  19.   
  20.     static {  
  21.         String basePackage = ConfigHelper.getAppBasePackage();  
  22.         CLASS_SET = ClassUtil.getClassSet(basePackage);  
  23.     }  
  24.   
  25.     /** 
  26.      * 获取应用包下的所有类 
  27.      */  
  28.     public static Set<Class<?>> getClassSet() {  
  29.         return CLASS_SET;  
  30.     }  
  31.   
  32.     /** 
  33.      * 获取应用包名下所有Service类 
  34.      */  
  35.     public static Set<Class<?>> getServiceClassSet() {  
  36.         Set<Class<?>> classSet = new HashSet<Class<?>>();  
  37.         for (Class<?> cls : CLASS_SET) {  
  38.             if (cls.isAnnotationPresent(Service.class)) {  
  39.                 classSet.add(cls);  
  40.             }  
  41.         }  
  42.         return classSet;  
  43.     }  
  44.   
  45.     /** 
  46.      * 获取应用包名下所有Controller类 
  47.      */  
  48.     public static Set<Class<?>> getControllerClassSet() {  
  49.         Set<Class<?>> classSet = new HashSet<Class<?>>();  
  50.         for (Class<?> cls : CLASS_SET) {  
  51.             if (cls.isAnnotationPresent(Controller.class)) {  
  52.                 classSet.add(cls);  
  53.             }  
  54.         }  
  55.         return classSet;  
  56.     }  
  57.     /** 
  58.      * 获取应用包名下所有Bean类(包括Service,Controller) 
  59.      */  
  60.     public static Set<Class<?>> getBeanClassSet() {  
  61.        Set<Class<?>> beanClassSet = new HashSet<Class<?>>();  
  62.        beanClassSet.addAll(getServiceClassSet());  
  63.        beanClassSet.addAll(getControllerClassSet());  
  64.         return beanClassSet;  
  65.     }  
  66. }  


     像上面这样,我们使用ClassHelper封装了ClassUtil,并提供了一系列的助手方法,通过这些方法我们可以直接获取我们想要的类集合,在后面的我们会经常使用到ClassHelper。

阅读全文
0 0
原创粉丝点击