聊一聊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; } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。