分享java类的扫描代码

1.按照指定包扫描
2.按照指定注解类过滤
  1. package com.bswan;

  2. import java.io.IOException;
  3. import java.lang.annotation.Annotation;
  4. import java.util.HashSet;
  5. import java.util.LinkedList;
  6. import java.util.List;
  7. import java.util.Set;

  8. import org.apache.log4j.Logger;
  9. import org.springframework.beans.factory.BeanDefinitionStoreException;
  10. import org.springframework.context.ResourceLoaderAware;
  11. import org.springframework.core.io.Resource;
  12. import org.springframework.core.io.ResourceLoader;
  13. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
  14. import org.springframework.core.io.support.ResourcePatternResolver;
  15. import org.springframework.core.io.support.ResourcePatternUtils;
  16. import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
  17. import org.springframework.core.type.classreading.MetadataReader;
  18. import org.springframework.core.type.classreading.MetadataReaderFactory;
  19. import org.springframework.core.type.filter.AnnotationTypeFilter;
  20. import org.springframework.core.type.filter.TypeFilter;
  21. import org.springframework.util.ClassUtils;
  22. import org.springframework.util.SystemPropertyUtils;

  23. import core.plugin.table.Table;
  24. import core.route.Controllers;
  25. @SuppressWarnings({ "rawtypes", "unchecked" })
  26. public class ClassScaner implements ResourceLoaderAware {
  27.     /**
  28.      * log
  29.      */
  30.     private static Logger logger = Logger.getLogger(ClassScaner.class);
  31.      
  32.     private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

  33.     private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();

  34.     private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();

  35.     private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
  36.             this.resourcePatternResolver);

  37.     public ClassScaner() {

  38.     }

  39.     public void setResourceLoader(ResourceLoader resourceLoader) {
  40.         this.resourcePatternResolver = ResourcePatternUtils
  41.                 .getResourcePatternResolver(resourceLoader);
  42.         this.metadataReaderFactory = new CachingMetadataReaderFactory(
  43.                 resourceLoader);
  44.     }

  45.     public final ResourceLoader getResourceLoader() {
  46.         return this.resourcePatternResolver;
  47.     }

  48.     public void addIncludeFilter(TypeFilter includeFilter) {
  49.         this.includeFilters.add(includeFilter);
  50.     }

  51.     public void addExcludeFilter(TypeFilter excludeFilter) {
  52.         this.excludeFilters.add(0, excludeFilter);
  53.     }

  54.     public void resetFilters(boolean useDefaultFilters) {
  55.         this.includeFilters.clear();
  56.         this.excludeFilters.clear();
  57.     }

  58.     public static Set<Class> scan(String basePackage,Class<? extends Annotation>... annotations) {
  59.         ClassScaner cs = new ClassScaner();
  60.         for (Class anno : annotations){
  61.             cs.addIncludeFilter(new AnnotationTypeFilter(anno));
  62.         }
  63.         return cs.doScan(basePackage);
  64.     }

  65.     public static Set<Class> scan(String[] basePackages,Class<? extends Annotation>... annotations) {
  66.         ClassScaner cs = new ClassScaner();
  67.         for (Class anno : annotations){
  68.             cs.addIncludeFilter(new AnnotationTypeFilter(anno));
  69.         }
  70.         Set<Class> classes = new HashSet<Class>();
  71.         for (String s : basePackages){
  72.             classes.addAll(cs.doScan(s));
  73.         }
  74.         return classes;
  75.     }

  76.     public Set<Class> doScan(String basePackage) {
  77.         Set<Class> classes = new HashSet<Class>();
  78.         try {
  79.             String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage))+ "/**/*.class";
  80.             System.out.println(packageSearchPath);
  81.             Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
  82.             for (int i = 0; i < resources.length; i++) {
  83.                 Resource resource = resources[i];
  84.                 System.out.println(resource.getFilename());
  85.                 if (resource.isReadable()) {
  86.                     MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
  87.                     if ((includeFilters.size() == 0 && excludeFilters.size() == 0)|| matches(metadataReader)) {
  88.                         try {
  89.                             classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
  90.                         } catch (ClassNotFoundException e) {
  91.                             logger.error(e.getMessage());
  92.                         }
  93.                     }
  94.                 }
  95.             }
  96.         } catch (IOException ex) {
  97.             throw new BeanDefinitionStoreException(
  98.                     "I/O failure during classpath scanning", ex);
  99.         }
  100.         return classes;
  101.     }

  102.     protected boolean matches(MetadataReader metadataReader) throws IOException {
  103.         for (TypeFilter tf : this.excludeFilters) {
  104.             if (tf.match(metadataReader, this.metadataReaderFactory)) {
  105.                 return false;
  106.             }
  107.         }
  108.         for (TypeFilter tf : this.includeFilters) {
  109.             if (tf.match(metadataReader, this.metadataReaderFactory)) {
  110.                 return true;
  111.             }
  112.         }
  113.         return false;
  114.     }
  115.      
  116.     public static void main(String[] args) {
  117.         Set<Class> set = ClassScaner.scan("com.bswan", Table.class,Controllers.class);
  118.         for (Class class1 : set) {
  119.             System.out.println(class1.getName());
  120.         }
  121.     }

  122. }扫描指定package下所有的类
  123. 思路:
    有的web server在部署运行时会解压jar包,因此class文件会在普通的文件目录下。如果web server不解压jar包,则class文件会直接存在于Jar包中。对于前者,只需定位到class文件所在目录,然后将class文件名读取出即可;对于后者,则需先定位到jar包所在目录,然后使用JarInputStream读取Jar包,得到class类名。网站推广

    实现:
    这是从写好的项目代码中直接copy出来的,如果要运行这段代码,需要把所有的Logger.debug改成System.out.println()

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    <code class = " hljs java" > /**
      * This scanner is used to find out all classes in a package.
      * Created by whf on 15-2-26.
      */
    public class ClasspathPackageScanner implements PackageScanner {
         private Logger logger = LoggerFactory.getLogger(ClasspathPackageScanner. class );
     
         private String basePackage;
         private ClassLoader cl;
     
         /**
          * Construct an instance and specify the base package it should scan.
          * @param basePackage The base package to scan.
          */
         public ClasspathPackageScanner(String basePackage) {
             this .basePackage = basePackage;
             this .cl = getClass().getClassLoader();
     
         }
     
         /**
          * Construct an instance with base package and class loader.
          * @param basePackage The base package to scan.
          * @param cl Use this class load to locate the package.
          */
         public ClasspathPackageScanner(String basePackage, ClassLoader cl) {
             this .basePackage = basePackage;
             this .cl = cl;
         }
     
         /**
          * Get all fully qualified names located in the specified package
          * and its sub-package.
          *
          * @return A list of fully qualified names.
          * @throws IOException
          */
         @Override
         public List<string> getFullyQualifiedClassNameList() throws IOException {
             logger.info( "开始扫描包{}下的所有类" , basePackage);
     
             return doScan(basePackage, new ArrayList<>());
         }
     
         /**
          * Actually perform the scanning procedure.
          *
          * @param basePackage
          * @param nameList A list to contain the result.
          * @return A list of fully qualified names.
          *
          * @throws IOException
          */
         private List<string> doScan(String basePackage, List<string> nameList) throws IOException {
             // replace dots with splashes
             String splashPath = StringUtil.dotToSplash(basePackage);
     
             // get file path
             URL url = cl.getResource(splashPath);
             String filePath = StringUtil.getRootPath(url);
     
             // Get classes in that package.
             // If the web server unzips the jar file, then the classes will exist in the form of
             // normal file in the directory.
             // If the web server does not unzip the jar file, then classes will exist in jar file.
             List<string> names = null ; // contains the name of the class file. e.g., Apple.class will be stored as "Apple"
             if (isJarFile(filePath)) {
                 // jar file
                 if (logger.isDebugEnabled()) {
                     logger.debug( "{} 是一个JAR包" , filePath);
                 }
     
                 names = readFromJarFile(filePath, splashPath);
             } else {
                 // directory
                 if (logger.isDebugEnabled()) {
                     logger.debug( "{} 是一个目录" , filePath);
                 }
     
                 names = readFromDirectory(filePath);
             }
     
             for (String name : names) {
                 if (isClassFile(name)) {
                     //nameList.add(basePackage + "." + StringUtil.trimExtension(name));
                     nameList.add(toFullyQualifiedName(name, basePackage));
                 } else {
                     // this is a directory
                     // check this directory for more classes
                     // do recursive invocation
                     doScan(basePackage + "." + name, nameList);
                 }
             }
     
             if (logger.isDebugEnabled()) {
                 for (String n : nameList) {
                     logger.debug( "找到{}" , n);
                 }
             }
     
             return nameList;
         }
     
         /**
          * Convert short class name to fully qualified name.
          * e.g., String -> java.lang.String
          */
         private String toFullyQualifiedName(String shortName, String basePackage) {
             StringBuilder sb = new StringBuilder(basePackage);
             sb.append( '.' );
             sb.append(StringUtil.trimExtension(shortName));
     
             return sb.toString();
         }
     
         private List<string> readFromJarFile(String jarPath, String splashedPackageName) throws IOException {
             if (logger.isDebugEnabled()) {
                 logger.debug( "从JAR包中读取类: {}" , jarPath);
             }
     
             JarInputStream jarIn = new JarInputStream( new FileInputStream(jarPath));
             JarEntry entry = jarIn.getNextJarEntry();
     
             List<string> nameList = new ArrayList<>();
             while ( null != entry) {
                 String name = entry.getName();
                 if (name.startsWith(splashedPackageName) && isClassFile(name)) {
                     nameList.add(name);
                 }
     
                 entry = jarIn.getNextJarEntry();
             }
     
             return nameList;
         }
     
         private List<string> readFromDirectory(String path) {
             File file = new File(path);
             String[] names = file.list();
     
             if ( null == names) {
                 return null ;
             }
     
             return Arrays.asList(names);
         }
     
         private boolean isClassFile(String name) {
             return name.endsWith( ".class" );
         }
     
         private boolean isJarFile(String name) {
             return name.endsWith( ".jar" );
         }
     
         /**
          * For test purpose.
          */
         public static void main(String[] args) throws Exception {
             PackageScanner scan = new ClasspathPackageScanner( "cn.fh.lightning.bean" );
             scan.getFullyQualifiedClassNameList();
         }
     
    }</string></string></string></string></string></string></string></code>

    上面的代码中用到了StringUtils类,如下:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    <code class = " hljs java" > public class StringUtil {
         private StringUtil() {
     
         }
     
         /**
          * "file:/home/whf/cn/fh" -> "/home/whf/cn/fh"
          * "jar:file:/home/whf/foo.jar!cn/fh" -> "/home/whf/foo.jar"
          */
         public static String getRootPath(URL url) {
             String fileUrl = url.getFile();
             int pos = fileUrl.indexOf( '!' );
     
             if (- 1 == pos) {
                 return fileUrl;
             }
     
             return fileUrl.substring( 5 , pos);
         }
     
         /**
          * "cn.fh.lightning" -> "cn/fh/lightning"
          * @param name
          * @return
          */
         public static String dotToSplash(String name) {
             return name.replaceAll( "\\." , "/" );
         }
     
         /**
          * "Apple.class" -> "Apple"
          */
         public static String trimExtension(String name) {
             int pos = name.indexOf( '.' );
             if (- 1 != pos) {
                 return name.substring( 0 , pos);
             }
     
             return name;
         }
     
         /**
          * /application/home -> /home
          * @param uri
          * @return
          */
         public static String trimURI(String uri) {
             String trimmed = uri.substring( 1 );
             int splashIndex = trimmed.indexOf( '/' );
     
             return trimmed.substring(splashIndex);
         }
    }</code>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值