聊一聊Java反射
这次提到的Java反射涉及的代码比较多。因为工作中经常用到反射,对代码做了很多抽象以及过滤器。虽然代码量很多,但是简单易用,过滤插件也易修改。
下面介绍下工作中哪些地方比较容易用到反射。比如插件或者过滤器,如果抽象的子类比较少,配置成XML等结构也是可以达到同样的效果。如果希望灵活一些,添加了插件或者过滤器代码子类后希望可以直接使用。可能反射会比较好点,通过扫描所有class或者jar文件,得到所有继承的子类。如果每次调用都扫描所有的文件会比较影响性能。所以在实现里面加入反射缓存,对所要获取反射子类时涉及的所有参数作为一个key缓存所有的反射结果。下次如果是同样的key,就不在重新扫描。
代码示例如下:
publicstaticvoidmain(String[]args){
//设置扫描范围,可以是class文件所在位置例如bin下或者是mysql开头或者mysql结尾的jar,
//设置为""为全部都扫描,这种比较耗时
ReflectUtils.createSharedReflections("classes","bin","mysql");
try{
//调试阶段可以设置每次都全扫描
//Beans.setDesignTime(true);
finalCollection<String>subTypes=ReflectUtils.listSubClass(IA.class);//
for(finalStringsubType:subTypes){
//这里获取的是所有继承IA的子类
System.out.println(subType);
finalIAimpl=ReflectUtils.initClass(subType,IA.class);
if(null==impl)
continue;
//通过该方式,可以统一做操作,
impl.print();
}
}catch(Exceptione){
e.printStackTrace();
}
}
代码执行结果:
//缓存文件,避免每次调用反射都重新扫描 //如果删除该文件,再次调用反射时,会重新扫描,一般会在代码里面有添加子类的时候会删除该文件 XmlUtils.readXmlfailure:.\configuration.REF(系统找不到指定的文件。) net.simple.reflect.test.B net.simple.reflect.test.B net.simple.reflect.test.D net.simple.reflect.test.V
具体的类里面如何实现的大家就看下源码吧,这里贴出两个核心类的代码。源码地址:https://git.oschina.net/eliyanfei/api_tools
packagenet.simple.reflect;
importjava.io.File;
importjava.io.IOException;
importjava.net.JarURLConnection;
importjava.net.URL;
importjava.net.URLDecoder;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.Enumeration;
importjava.util.LinkedHashMap;
importjava.util.List;
importjava.util.Map;
importjava.util.concurrent.TimeUnit;
importjava.util.jar.JarEntry;
importjava.util.jar.JarFile;
importjava.util.zip.ZipEntry;
importnet.simple.reflect.filter.IPathURLFilter;
importnet.simple.reflect.filter.ISubTypeFilter;
importnet.simple.reflect.filter.ITypeFilter;
importorg.w3c.dom.Document;
importorg.w3c.dom.Element;
/**
*
*@author李岩飞
*@emaileliyanfei@126.com
*2016年11月2日下午3:23:49
*
*/
publicfinalclassReflections{
privatefinalCollection<URL>pathUrls;
privatefinalCollection<IPathURLFilter>pathURLfilters;
privatefinalCollection<ITypeFilter>typeFilters;
privateISubTypeFiltersubTypeFilter;
publicReflections(){
typeFilters=newArrayList<ITypeFilter>();
pathURLfilters=newArrayList<IPathURLFilter>();
this.pathUrls=ClasspathHelper.getUrlsForCurrentClasspath();
}
publicReflections(finalCollection<URL>pathUrls){
this.pathUrls=pathUrls;
typeFilters=newArrayList<ITypeFilter>();
pathURLfilters=newArrayList<IPathURLFilter>();
}
/**
*@paramsubTypeFilter
*thesubTypeFiltertoset
*/
publicvoidsetSubTypeFilter(finalISubTypeFiltersubTypeFilter){
this.subTypeFilter=subTypeFilter;
}
/**
*@returnthesubTypeFilter
*/
publicISubTypeFiltergetSubTypeFilter(){
returnsubTypeFilter;
}
publicReflectionsaddPathURLFilter(finalIPathURLFilterpathURLFilter){
if(null==pathURLFilter)
returnthis;
if(!this.pathURLfilters.contains(pathURLFilter))
this.pathURLfilters.add(pathURLFilter);
returnthis;
}
publicReflectionsaddTypeFilter(finalITypeFiltertypeFilter){
if(null==typeFilter)
returnthis;
if(!this.typeFilters.contains(typeFilter))
this.typeFilters.add(typeFilter);
returnthis;
}
privatestaticfinalStringhistFile="./configuration.REF";
privateDocumenthistDom;
publicCollection<String>getSubTypesFast(finalClass<?>baseType){//,finalString...typeNames
//首先过滤出当前允许扫描的路径
finalStringBuilderbufPathsId=newStringBuilder(32);
finalMap<File,URL>fileUrls=newLinkedHashMap<File,URL>(8);
for(finalURLpathUrl:pathUrls){
if(!acceptPathUrl(pathUrl))
continue;
Filefile=null;
try{
file=newFile(URLDecoder.decode(pathUrl.getFile(),"UTF-8"));
}catch(finalExceptione){
file=newFile(pathUrl.getFile());
}
fileUrls.put(file,pathUrl);
if(!file.exists())//isurlfile?ignore
continue;
bufPathsId.append(file.getName()).append(file.lastModified());
}
finalStringdomId=MD5.getHashString(bufPathsId.toString());
if(null==histDom)
histDom=W3cUtils.readXml(histFile);
if(null==histDom)
histDom=W3cUtils.newDom("R");
ElementrootEle=histDom.getDocumentElement();
if(null==rootEle)
histDom.appendChild(rootEle=histDom.createElement("R"));
if(!domId.equals(rootEle.getAttribute("id"))){
rootEle.getParentNode().removeChild(rootEle);
histDom.appendChild(rootEle=histDom.createElement("R"));
rootEle.setAttribute("id",domId);
}
finalStringbaseTypeId=MD5.getHashString(baseType.getName());
ElementrefEle=W3cUtils.firstChildElement(rootEle,"E","id",baseTypeId);
if(null!=refEle){
finalList<Element>valueEles=W3cUtils.childElementList(refEle,"F");
finalCollection<String>result=newArrayList<String>(valueEles.size());
for(finalElementvalueEle:valueEles){
result.add(newString(Base64.decodeFast(valueEle.getAttribute("id"))));
}
returnresult;
}
finalThreadPool<ListSubTypes>pool=newThreadPool<ListSubTypes>();
for(finalFilefileKey:fileUrls.keySet()){
pool.execute(newListSubTypes(baseType,fileKey,fileUrls.get(fileKey)));
}
try{
pool.shutdown(3,TimeUnit.MINUTES);
}catch(finalInterruptedExceptione){
e.printStackTrace();//fordebug
}
finalCollection<String>result=newArrayList<String>();
for(finalListSubTypestask:pool.getThreadRunables()){
result.addAll(task.result);
}
refEle=W3cUtils.addEle(rootEle,"E");
refEle.setAttribute("id",baseTypeId);
for(finalStringitm:result){
W3cUtils.addEle(refEle,"F").setAttribute("id",Base64.encodeToString(itm.getBytes(),false));
}
try{
W3cUtils.writeXmlDocument(histFile,histDom);
}catch(finalExceptione){
}
returnresult;
}
/**
*@see{@linkReflectUtils#createSharedReflections(String...)}
*@see{@linkReflectUtils#setSharedReflections(Reflections)}
*@see{@linkReflectUtils#listSubClass(Class)}
*@parambaseType
*@return
*/
publicCollection<String>getSubTypes(finalClass<?>baseType,finalString...typeNames){//
finalThreadPool<ListSubTypes>pool=newThreadPool<ListSubTypes>();
for(finalURLpathUrl:pathUrls){
if(!acceptPathUrl(pathUrl))
continue;
Filefile=null;
try{
file=newFile(URLDecoder.decode(pathUrl.getFile(),"UTF-8"));
}catch(finalExceptione){
file=newFile(pathUrl.getFile());
}
pool.execute(newListSubTypes(baseType,file,pathUrl,typeNames));
}
try{
pool.shutdown(3,TimeUnit.MINUTES);
}catch(finalInterruptedExceptione){
e.printStackTrace();//fordebug
}
finalCollection<String>result=newArrayList<String>();
for(finalListSubTypestask:pool.getThreadRunables()){
result.addAll(task.result);
}
returnresult;
}
classListSubTypesimplementsRunnable{
finalFilefile;
finalClass<?>baseType;
finalURLpathUrl;
finalString[]typeNames;
publicListSubTypes(finalClass<?>baseType,finalFilefile,finalURLpathUrl,finalString...typeNames){
this.baseType=baseType;
this.file=file;
this.pathUrl=pathUrl;
this.typeNames=typeNames;
}
Collection<String>result=newArrayList<String>(4);
@Override
publicvoidrun(){
if(file.isDirectory()){
listSubTypesFromDirectory(file,baseType,pathUrl,file,result,typeNames);
}else
listSubTypesFromJar(baseType,pathUrl,result,typeNames);
}
}
/**
*@parambaseType
*@parampathUrl
*@paramresult
*/
publicvoidlistSubTypesFromDirectory(finalFilebaseDirectory,finalClass<?>baseType,finalURLpathUrl,finalFiledirectory,
finalCollection<String>result,finalString...typeNames){
File[]files=directory.listFiles();
if(null==files)
files=newFile[]{};
StringclazzPath;
finalintbaseDirLen=baseDirectory.getAbsolutePath().length()+1;
for(finalFilefile:files){
if(file.isDirectory()){
listSubTypesFromDirectory(baseDirectory,baseType,pathUrl,file,result,typeNames);
}else{
clazzPath=file.getAbsolutePath().substring(baseDirLen);
clazzPath=clazzPath.replace('\\','/');
doTypesFilter(baseType,pathUrl,result,clazzPath,typeNames);
}
}
}
/**
*@parambaseType
*@parampathUrl
*@paramresult
*/
publicvoidlistSubTypesFromJar(finalClass<?>baseType,URLpathUrl,finalCollection<String>result,finalString...typeNames){
try{
//Itdoesnotworkwiththefilesystem:wemust
//beinthecaseofapackagecontainedinajarfile.
JarFilejarFile=null;
try{
if("file".equals(pathUrl.getProtocol()))
pathUrl=newURL("jar:"+pathUrl.toExternalForm()+"!/");
jarFile=((JarURLConnection)pathUrl.openConnection()).getJarFile();
}catch(finalExceptione){
finalStringfilePath=pathUrl.getFile();
//ifonwinplatform
if(filePath.indexOf(':')!=-1){
if(pathUrl.getFile().charAt(0)=='/')
jarFile=newJarFile(filePath.substring(1));
}
if(null==jarFile)
jarFile=newJarFile(filePath);
}
finalEnumeration<JarEntry>e=jarFile.entries();
ZipEntryentry;
while(e.hasMoreElements()){
entry=e.nextElement();
doTypesFilter(baseType,pathUrl,result,entry.getName(),typeNames);
}
}catch(finalIOExceptionioex){
}
}
privatevoiddoTypesFilter(finalClass<?>baseType,finalURLpathUrl,finalCollection<String>result,finalStringclazzPath,
finalString...typeNames){
if(!clazzPath.endsWith(".class"))
return;
finalintlastDotIdx=clazzPath.lastIndexOf('.');
if(-1==lastDotIdx)
return;
finalStringtypeDef=clazzPath.substring(0,lastDotIdx).replace('/','.');
if(null!=typeNames&&typeNames.length>0){
finalintlastDot=typeDef.lastIndexOf('.');
if(lastDot==-1)
return;
finalStringtypeName=typeDef.substring(lastDot+1);
booleanwithLiked=false;
for(finalStringtmpTypeName:typeNames){
if(!typeName.contains(tmpTypeName))
continue;
withLiked=true;
break;
}
if(withLiked==false)
return;
}
if(this.typeFilters.isEmpty()){
if(null==this.subTypeFilter||this.subTypeFilter.accept(baseType,pathUrl,clazzPath))
result.add(typeDef);
}else{
for(finalITypeFiltertypeFilter:this.typeFilters){
if(!typeFilter.accept(clazzPath))
continue;
if(null==this.subTypeFilter||this.subTypeFilter.accept(baseType,pathUrl,clazzPath))
result.add(typeDef);
}
}
}
/**
*@parampathUrl
*@return
*/
privatebooleanacceptPathUrl(finalURLpathUrl){
if(this.pathURLfilters.isEmpty())
returntrue;
for(finalIPathURLFilterpathURLFilter:this.pathURLfilters){
if(pathURLFilter.accept(pathUrl))
returntrue;
}
returnfalse;
}
}
packagenet.simple.reflect;
importjava.beans.Beans;
importjava.io.File;
importjava.io.IOException;
importjava.io.UnsupportedEncodingException;
importjava.net.JarURLConnection;
importjava.net.URL;
importjava.net.URLDecoder;
importjava.util.ArrayList;
importjava.util.Collection;
importjava.util.Collections;
importjava.util.Enumeration;
importjava.util.List;
importjava.util.jar.JarEntry;
importjava.util.jar.JarFile;
importjava.util.zip.ZipEntry;
importnet.simple.reflect.filter.PathURLFilter;
importnet.simple.reflect.filter.SampleSubInstanceFilter;
importnet.simple.reflect.filter.TypeFilter;
/**
*
*@author李岩飞
*@emaileliyanfei@126.com
*2016年11月2日下午3:24:02
*
*/
publicfinalclassReflectUtils{
publicstaticfinalStringVAR_START_FLAG="${";
publicstaticfinalStringVAR_END_FLAG="}";
privatestaticReflectionssharedReflections;
staticfinalCollection<String>EMP_COLL=Collections.emptyList();
publicstaticfinalvoidcreateSharedReflections(finalString...filterExts){
finalReflectionsrefs=newReflections();
refs.addPathURLFilter(newPathURLFilter(filterExts));//
refs.addTypeFilter(TypeFilter.DEFAULT);
refs.setSubTypeFilter(SampleSubInstanceFilter.DEFAULT);
ReflectUtils.setSharedReflections(refs);
}
/**
*此方法用于绑定一个通用的共享类型遍列工具.
*@paramsharedReflections
*/
publicstaticfinalvoidsetSharedReflections(finalReflectionssharedReflections){
ReflectUtils.sharedReflections=sharedReflections;
}
/**
*调用此方法之前必须先设置共享的类型遍列工具,参考:{@link#setSharedReflections(Reflections)},
*此方法主要使更方便的遍列给定类的实现,
*/
publicstaticfinalCollection<String>listSubClass(finalClass<?>baseType,finalString...typeNames){//
if(null==sharedReflections)
returnEMP_COLL;
//调用阶段由于可能增加新的子类实现,需要每次都重新扫描,只有在发布的产品时使用保存记录的方法以提高启动速度.
returnBeans.isDesignTime()?sharedReflections.getSubTypes(baseType,typeNames):sharedReflections.getSubTypesFast(baseType);
}
publicstaticList<Class<?>>listClassOfPackage(finalClass<?>cType,finalStringextenion){
finalList<Class<?>>result=newArrayList<Class<?>>();
finalList<String>cPath=ReflectUtils.listClassCanonicalNameOfPackage(cType,extenion);
for(finalStringpath:cPath){
try{
result.add(Class.forName(path,false,Thread.currentThread().getContextClassLoader()));
}catch(finalExceptione){
//ignore
}
}
returnresult;
}
publicstaticList<String>listClassCanonicalNameOfPackage(finalClass<?>clazz,finalStringextenion){
returnReflectUtils.listNameOfPackage(clazz,extenion,true);
}
publicstaticList<String>listClassNameOfPackage(finalClass<?>clazz,finalStringextenion){
returnReflectUtils.listNameOfPackage(clazz,extenion,false);
}
publicstaticList<String>listNameOfPackage(finalClass<?>clazz,finalStringextenion,finalbooleanfullPkgName){
returnReflectUtils.listNameOfPackage(clazz.getName().replace('.','/')+".class",extenion,fullPkgName);
}
publicstaticList<String>listNameOfPackage(finalStringclazzPkg,finalStringextenion,finalbooleanfullPkgName){
finalList<String>result=newArrayList<String>();
finalStringBufferpkgBuf=newStringBuffer(clazzPkg);
if(pkgBuf.charAt(0)!='/')
pkgBuf.insert(0,'/');
finalURLurlPath=ReflectUtils.class.getResource(pkgBuf.toString());
if(null==urlPath)
returnresult;
StringcheckedExtenion=extenion;
if(!extenion.endsWith(".class"))
checkedExtenion=extenion+".class";
if(pkgBuf.toString().endsWith(".class"))
pkgBuf.delete(pkgBuf.lastIndexOf("/"),pkgBuf.length());
pkgBuf.deleteCharAt(0);
finalStringBufferfileUrl=newStringBuffer();
try{
fileUrl.append(URLDecoder.decode(urlPath.toExternalForm(),"UTF-8"));
}catch(finalUnsupportedEncodingExceptione1){
fileUrl.append(urlPath.toExternalForm());
}
if(fileUrl.toString().startsWith("file:")){
fileUrl.delete(0,5);//deletefile:flag
if(fileUrl.indexOf(":")!=-1)
fileUrl.deleteCharAt(0);//deleteflag
finalStringbaseDir=fileUrl.substring(0,fileUrl.lastIndexOf("classes")+8);
ReflectUtils.doListNameOfPackageInDirectory(newFile(baseDir),newFile(baseDir),result,pkgBuf.toString(),checkedExtenion,fullPkgName);
}else{
ReflectUtils.doListNameOfPackageInJar(urlPath,urlPath,result,pkgBuf.toString(),checkedExtenion,fullPkgName);
}
returnresult;
}
/**
*/
privatestaticvoiddoListNameOfPackageInJar(finalURLbaseUrl,finalURLurlPath,finalList<String>result,finalStringclazzPkg,finalStringextenion,finalbooleanfullPkgName){
try{
//Itdoesnotworkwiththefilesystem:wemust
//beinthecaseofapackagecontainedinajarfile.
finalJarURLConnectionconn=(JarURLConnection)urlPath.openConnection();
finalJarFilejfile=conn.getJarFile();
finalEnumeration<JarEntry>e=jfile.entries();
ZipEntryentry;
Stringentryname;
while(e.hasMoreElements()){
entry=e.nextElement();
entryname=entry.getName();
if(entryname.startsWith(clazzPkg)&&entryname.endsWith(extenion)){
if(fullPkgName)
result.add(entryname.substring(0,entryname.lastIndexOf('.')).replace('/','.'));
else
result.add(entryname.substring(entryname.lastIndexOf('/')+1,entryname.lastIndexOf('.')));
}
}
}catch(finalIOExceptionioex){
}
}
privatestaticvoiddoListNameOfPackageInDirectory(finalFilebaseDirectory,finalFiledirectory,finalList<String>result,finalStringclazzPkg,finalStringextenion,
finalbooleanfullPkgName){
File[]files=directory.listFiles();
if(null==files)
files=newFile[]{};
StringclazzPath;
finalintbaseDirLen=baseDirectory.getAbsolutePath().length()+1;
for(finalFilefile:files){
if(file.isDirectory()){
ReflectUtils.doListNameOfPackageInDirectory(baseDirectory,file,result,clazzPkg,extenion,fullPkgName);
}else{
if(!file.getName().endsWith(extenion))
continue;
if(fullPkgName){
clazzPath=file.getAbsolutePath().substring(baseDirLen);
clazzPath=clazzPath.substring(0,clazzPath.length()-6);
result.add(clazzPath.replace(File.separatorChar,'.'));
}else{
result.add(file.getName().substring(0,file.getName().length()-6));
}
}
}
}
publicstaticfinal<T>TinitClass(finalStringimplClass,finalClass<T>tType){
returnReflectUtils.initClass(implClass,tType,true);
}
publicstaticfinal<T>TinitClass(finalStringimplClass,finalClass<T>tType,finalbooleandoInit){
try{
finalObjectobject=Class.forName(implClass,doInit,Thread.currentThread().getContextClassLoader()).newInstance();
returntType.cast(object);
}catch(finalThrowablee){
returnnull;
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。