1.按照指定包扫描
2.按照指定注解类过滤
2.按照指定注解类过滤
- package com.bswan;
- import java.io.IOException;
- import java.lang.annotation.Annotation;
- import java.util.HashSet;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Set;
- import org.apache.log4j.Logger;
- import org.springframework.beans.factory.BeanDefinitionStoreException;
- import org.springframework.context.ResourceLoaderAware;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.ResourceLoader;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.core.io.support.ResourcePatternResolver;
- import org.springframework.core.io.support.ResourcePatternUtils;
- import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
- import org.springframework.core.type.classreading.MetadataReader;
- import org.springframework.core.type.classreading.MetadataReaderFactory;
- import org.springframework.core.type.filter.AnnotationTypeFilter;
- import org.springframework.core.type.filter.TypeFilter;
- import org.springframework.util.ClassUtils;
- import org.springframework.util.SystemPropertyUtils;
- import core.plugin.table.Table;
- import core.route.Controllers;
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public class ClassScaner implements ResourceLoaderAware {
- /**
- * log
- */
- private static Logger logger = Logger.getLogger(ClassScaner.class);
-
- private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
- private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();
- private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
- private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
- this.resourcePatternResolver);
- public ClassScaner() {
- }
- public void setResourceLoader(ResourceLoader resourceLoader) {
- this.resourcePatternResolver = ResourcePatternUtils
- .getResourcePatternResolver(resourceLoader);
- this.metadataReaderFactory = new CachingMetadataReaderFactory(
- resourceLoader);
- }
- public final ResourceLoader getResourceLoader() {
- return this.resourcePatternResolver;
- }
- public void addIncludeFilter(TypeFilter includeFilter) {
- this.includeFilters.add(includeFilter);
- }
- public void addExcludeFilter(TypeFilter excludeFilter) {
- this.excludeFilters.add(0, excludeFilter);
- }
- public void resetFilters(boolean useDefaultFilters) {
- this.includeFilters.clear();
- this.excludeFilters.clear();
- }
- public static Set<Class> scan(String basePackage,Class<? extends Annotation>... annotations) {
- ClassScaner cs = new ClassScaner();
- for (Class anno : annotations){
- cs.addIncludeFilter(new AnnotationTypeFilter(anno));
- }
- return cs.doScan(basePackage);
- }
- public static Set<Class> scan(String[] basePackages,Class<? extends Annotation>... annotations) {
- ClassScaner cs = new ClassScaner();
- for (Class anno : annotations){
- cs.addIncludeFilter(new AnnotationTypeFilter(anno));
- }
- Set<Class> classes = new HashSet<Class>();
- for (String s : basePackages){
- classes.addAll(cs.doScan(s));
- }
- return classes;
- }
- public Set<Class> doScan(String basePackage) {
- Set<Class> classes = new HashSet<Class>();
- try {
- String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage))+ "/**/*.class";
- System.out.println(packageSearchPath);
- Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
- for (int i = 0; i < resources.length; i++) {
- Resource resource = resources[i];
- System.out.println(resource.getFilename());
- if (resource.isReadable()) {
- MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
- if ((includeFilters.size() == 0 && excludeFilters.size() == 0)|| matches(metadataReader)) {
- try {
- classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
- } catch (ClassNotFoundException e) {
- logger.error(e.getMessage());
- }
- }
- }
- }
- } catch (IOException ex) {
- throw new BeanDefinitionStoreException(
- "I/O failure during classpath scanning", ex);
- }
- return classes;
- }
- protected boolean matches(MetadataReader metadataReader) throws IOException {
- for (TypeFilter tf : this.excludeFilters) {
- if (tf.match(metadataReader, this.metadataReaderFactory)) {
- return false;
- }
- }
- for (TypeFilter tf : this.includeFilters) {
- if (tf.match(metadataReader, this.metadataReaderFactory)) {
- return true;
- }
- }
- return false;
- }
-
- public static void main(String[] args) {
- Set<Class> set = ClassScaner.scan("com.bswan", Table.class,Controllers.class);
- for (Class class1 : set) {
- System.out.println(class1.getName());
- }
- }
- }扫描指定package下所有的类
-
思路:
有的web server在部署运行时会解压jar包,因此class文件会在普通的文件目录下。如果web server不解压jar包,则class文件会直接存在于Jar包中。对于前者,只需定位到class文件所在目录,然后将class文件名读取出即可;对于后者,则需先定位到jar包所在目录,然后使用JarInputStream
读取Jar包,得到class类名。网站推广实现:
这是从写好的项目代码中直接copy出来的,如果要运行这段代码,需要把所有的Logger.debug
改成System.out.println()
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164<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
类,如下:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253<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>