The Java reflection mentioned this time involves a lot of code. Because reflection is often used in work, we have made a lot of abstractions and filters to the code. Although the code is large, it is simple and easy to use, and filter plug-ins are also easy to modify.
The following is a description of where reflection is easier to use in work. For example, plug-ins or filters, if there are fewer abstract subclasses, configuring them to XML and other structures can also achieve the same effect. If you want to be more flexible, you can use it directly after adding plug-ins or filter code subclasses. It may be better to reflect, and all inherited subclasses are obtained by scanning all class or jar files. If you scan all files every call, it will affect performance. Therefore, a reflection cache is added to the implementation to cache all the reflection results as a key for all the parameters involved in obtaining the reflection subclass. If it is the same key next time, you won't rescan.
The code example is as follows:
public static void main(String[] args) { //Set the scan range, which can be the location of the class file, such as the location under bin, or the beginning of mysql or the end of mysql, //Set "" to scan all, this is time-consuming, ReflectUtils.createSharedReflections("classes", "bin", "mysql"); try { //You can set full scans every time in the debugging stage//Beans.setDesignTime(true); final Collection<String> subTypes = ReflectUtils.listSubClass(IA.class);// for (final String subType : subTypes) { //What you get here are System.out.println(subType); final IA impl = ReflectUtils.initClass(subType, IA.class); if (null == impl) continue; //Through this method, you can perform operations in a unified manner, impl.print(); } } catch (Exception e) { e.printStackTrace(); } }Code execution result:
//Cache the file to avoid rescanning every time reflection is called //If you delete the file, it will be rescanned when the reflection is called again. Generally, the file will be deleted when there are subclasses in the code. XmlUtils.readXml failure:./configuration.REF (The system cannot find the specified file.) net.simple.reflect.test.Bnet.simple.reflect.test.Bnet.simple.reflect.test.Bnet.simple.reflect.test.Dnet.simple.reflect.test.V
For details, please see the source code. Here are two core classes codes. Source code address: https://git.oschina.net/eliyanfei/api_tools
package net.simple.reflect;import java.io.File;import java.io.IOException;import java.net.JarURLConnection;import java.net.URL;import java.net.URLDecoder;import java.util.ArrayList;import java.util.Collection;import java.util.Enumeration;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.concurrent.TimeUnit;import java.util.jar.JarEntry;import java.util.jar.JarFile;import java.util.zip.ZipEntry;import net.simple.reflect.filter.IPathURLFilter;import net.simple.reflect.filter.ISubTypeFilter;import net.simple.reflect.filter.ITypeFilter;import org.w3c.dom.Document;import org.w3c.dom.Element;/** * * @author Li Yanfei* @email [email protected] * November 2, 2016 at 3:23:49 pm * */public final class Reflections { private final Collection<URL> pathUrls; private final Collection<IPathURLFilter> pathURLfilters; private final Collection<ITypeFilter> typeFilters; private ISubTypeFilter subTypeFilter; public Reflections() { typeFilters = new ArrayList<ITypeFilter>(); pathURLfilters = new ArrayList<IPathURLFilter>(); this.pathUrls = ClasspathHelper.getUrlsForCurrentClasspath(); } public Reflections(final Collection<URL> pathUrls) { this.pathUrls = pathUrls; typeFilters = new ArrayList<ITypeFilter>(); pathURLfilters = new ArrayList<IPathURLFilter>(); } /** * @param subTypeFilter * the subTypeFilter to set */ public void setSubTypeFilter(final ISubTypeFilter subTypeFilter) { this.subTypeFilter = subTypeFilter; } /** * @return the subTypeFilter */ public ISubTypeFilter getSubTypeFilter() { return subTypeFilter; } public Reflections addPathURLFilter(final IPathURLFilter pathURLFilter) { if (null == pathURLFilter) return this; if (!this.pathURLfilters.contains(pathURLFilter)) this.pathURLfilters.add(pathURLFilter); return this; } public Reflections addTypeFilter(final ITypeFilter typeFilter) { if (null == typeFilter) return this; if (!this.typeFilters.contains(typeFilter)) this.typeFilters.add(typeFilter); return this; } private static final String histFile = "./configuration.REF"; private Document histDom; public Collection<String> getSubTypesFast(final Class<?> baseType) {//, final String... typeNames //First filter out the path currently allowed to scan final StringBuilder bufPathsId = new StringBuilder(32); final Map<File, URL> fileUrls = new LinkedHashMap<File, URL>(8); for (final URL pathUrl : pathUrls) { if (!acceptPathUrl(pathUrl)) continue; File file = null; try { file = new File(URLDecoder.decode(pathUrl.getFile(), "UTF-8")); } catch (final Exception e) { file = new File(pathUrl.getFile()); } fileUrls.put(file, pathUrl); if (!file.exists())//is url file?ignore continue; bufPathsId.append(file.getName()).append(file.lastModified()); } final String domId = MD5.getHashString(bufPathsId.toString()); if (null == histDom) hisDom = W3cUtils.readXml(histFile); if (null == histDom) hisDom = W3cUtils.newDom("R"); Element rootEle = 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); } final String baseTypeId = MD5.getHashString(baseType.getName()); Element refEle = W3cUtils.firstChildElement(rootEle, "E", "id", baseTypeId); if (null != refEle) { final List<Element> valueEles = W3cUtils.childElementList(refEle, "F"); final Collection<String> result = new ArrayList<String>(valueEles.size()); for (final Element valueEle: valueEles) { result.add(new String(Base64.decodeFast(valueEle.getAttribute("id")))); } return result; } final ThreadPool<ListSubTypes> pool = new ThreadPool<ListSubTypes>(); for (final File fileKey : fileUrls.keySet()) { pool.execute(new ListSubTypes(baseType, fileKey, fileUrls.get(fileKey))); } try { pool.shutdown(3, TimeUnit.MINUTES); } catch (final InterruptedException e) { e.printStackTrace();//for debug } final Collection<String> result = new ArrayList<String>(); for (final ListSubTypes task : pool.getThreadRunables()) { result.addAll(task.result); } refEle = W3cUtils.addEle(rootEle, "E"); refEle.setAttribute("id", baseTypeId); for (final String itm : result) { W3cUtils.addEle(refEle, "F").setAttribute("id", Base64.encodeToString(itm.getBytes(), false)); } try { W3cUtils.writeXmlDocument(histFile, histDom); } catch (final Exception e) { } return result; } /** * @see {@link ReflectUtils#createSharedReflections(String...)} * @see {@link ReflectUtils#setSharedReflections(Reflections)} * @see {@link ReflectUtils#listSubClass(Class)} * @param baseType * @return */ public Collection<String> getSubTypes(final Class<?> baseType, final String... typeNames) {// final ThreadPool<ListSubTypes> pool = new ThreadPool<ListSubTypes>(); for (final URL pathUrl : pathUrls) { if (!acceptPathUrl(pathUrl)) continue; File file = null; try { file = new File(URLDecoder.decode(pathUrl.getFile(), "UTF-8")); } catch (final Exception e) { file = new File(pathUrl.getFile()); } pool.execute(new ListSubTypes(baseType, file, pathUrl, typeNames)); } try { pool.shutdown(3, TimeUnit.MINUTES); } catch (final InterruptedException e) { e.printStackTrace();//for debug } final Collection<String> result = new ArrayList<String>(); for (final ListSubTypes task : pool.getThreadRunables()) { result.addAll(task.result); } return result; } class ListSubTypes implements Runnable { final File file; final Class<?> baseType; final URL pathUrl; final String[] typeNames; public ListSubTypes(final Class<?> baseType, final File file, final URL pathUrl, final String... typeNames) { this.baseType = baseType; this.file = file; this.pathUrl = pathUrl; this.typeNames = typeNames; } Collection<String> result = new ArrayList<String>(4); @Override public void run() { if (file.isDirectory()) { listSubTypesFromDirectory(file, baseType, pathUrl, file, result, typeNames); } else listSubTypesFromJar(baseType, pathUrl, result, typeNames); } } /** * @param baseType * @param pathUrl * @param result */ public void listSubTypesFromDirectory(final File baseDirectory, final Class<?> baseType, final URL pathUrl, final File directory, final Collection<String> result, final String... typeNames) { File[] files = directory.listFiles(); if (null == files) files = new File[] {}; String clazzPath; final int baseDirLen = baseDirectory.getAbsolutePath().length() + 1; for (final File file : 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); } } } /** * @param baseType * @param pathUrl * @param result */ public void listSubTypesFromJar(final Class<?> baseType, URL pathUrl, final Collection<String> result, final String... typeNames) { try { // It does not work with the filesystem: we must // be in the case of a package contained in a jar file. JarFile jarFile = null; try { if ("file".equals(pathUrl.getProtocol())) pathUrl = new URL("jar:" + pathUrl.toExternalForm() + "!/"); jarFile = ((JarURLConnection) pathUrl.openConnection()).getJarFile(); } catch (final Exception e) { final String filePath = pathUrl.getFile(); // if on win platform if (filePath.indexOf(':') != -1) { if (pathUrl.getFile().charAt(0) == '/') jarFile = new JarFile(filePath.substring(1)); } if (null == jarFile) jarFile = new JarFile(filePath); } final Enumeration<JarEntry> e = jarFile.entries(); ZipEntry entry; while (e.hasMoreElements()) { entry = e.nextElement(); doTypesFilter(baseType, pathUrl, result, entry.getName(), typeNames); } } catch (final IOException ioex) { } } private void doTypesFilter(final Class<?> baseType, final URL pathUrl, final Collection<String> result, final String clazzPath, final String... typeNames) { if (!clazzPath.endsWith(".class")) return; final int lastDotIdx = clazzPath.lastIndexOf('.'); if (-1 == lastDotIdx) return; final String typeDef = clazzPath.substring(0, lastDotIdx).replace('/', '.'); if (null != typeNames && typeNames.length > 0) { final int lastDot = typeDef.lastIndexOf('.'); if (lastDot == -1) return; final String typeName = typeDef.substring(lastDot + 1); boolean withLiked = false; for (final String tmpTypeName : 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 (final ITypeFilter typeFilter : this.typeFilters) { if (!typeFilter.accept(clazzPath)) continue; if (null == this.subTypeFilter || this.subTypeFilter.accept(baseType, pathUrl, clazzPath)) result.add(typeDef); } } } /** * @param pathUrl * @return */ private boolean acceptPathUrl(final URL pathUrl) { if (this.pathURLfilters.isEmpty()) return true; for (final IPathURLFilter pathURLFilter : this.pathURLfilters) { if (pathURLFilter.accept(pathUrl)) return true; } return false; }}
package net.simple.reflect;import java.beans.Beans;import java.io.File;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.JarURLConnection;import java.net.URL;import java.net.URLDecoder;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.Enumeration;import java.util.List;import java.util.jar.JarEntry;import java.util.jar.JarFile;import java.util.zip.ZipEntry;import net.simple.reflect.filter.PathURLFilter;import net.simple.reflect.filter.SampleSubInstanceFilter;import net.simple.reflect.filter.TypeFilter;/** * * @author Li Yanfei* @email [email protected] * November 2, 2016 at 3:24:02 pm * */public final class ReflectUtils { public static final String VAR_START_FLAG = "${"; public static final String VAR_END_FLAG = "}"; private static Reflections sharedReflections; static final Collection<String> EMP_COLL = Collections.emptyList(); public static final void createSharedReflections(final String... filterExts) { final Reflections refs = new Reflections(); refs.addPathURLFilter(new PathURLFilter(filterExts));// refs.addTypeFilter(TypeFilter.DEFAULT); refs.setSubTypeFilter(SampleSubInstanceFilter.DEFAULT); ReflectUtils.setSharedReflections(refs); } /** * This method is used to bind a common shared type circulating tool. * @param sharedReflections */ public static final void setSharedReflections(final Reflections sharedReflections) { ReflectUtils.sharedReflections = sharedReflections; } /** * Before calling this method, you must first set the shared type circumferential tool. Reference: {@link #setSharedReflections(Reflections)}, * This method mainly makes it more convenient to implement the given class, */ public static final Collection<String> listSubClass(final Class<?> baseType, final String... typeNames) {// if (null == sharedReflections) return EMP_COLL; // Since new subclass implementations may be added in the call stage, it is necessary to rescan each time. Only when the product is published, the method of saving records is used to improve the startup speed. return Beans.isDesignTime() ? sharedReflections.getSubTypes(baseType, typeNames) : sharedReflections.getSubTypesFast(baseType); } public static List<Class<?>> listClassOfPackage(final Class<?> cType, final String extension) { final List<Class<?>> result = new ArrayList<Class<?>>(); final List<String> cPath = ReflectUtils.listClassCanonicalNameOfPackage(cType, extension); for (final String path : cPath) { try { result.add(Class.forName(path, false, Thread.currentThread().getContextClassLoader())); } catch (final Exception e) { // ignore } } return result; } public static List<String> listClassCanonicalNameOfPackage(final Class<?> clazz, final String extension) { return ReflectUtils.listNameOfPackage(clazz, extension, true); } public static List<String> listClassNameOfPackage(final Class<?> clazz, final String extension) { return ReflectUtils.listNameOfPackage(clazz, extension, false); } public static List<String> listNameOfPackage(final Class<?> clazz, final String extension, final boolean fullPkgName) { return ReflectUtils.listNameOfPackage(clazz.getName().replace('.', '/') + ".class", extension, fullPkgName); } public static List<String> listNameOfPackage(final String clazzPkg, final String extension, final boolean fullPkgName) { final List<String> result = new ArrayList<String>(); final StringBuffer pkgBuf = new StringBuffer(clazzPkg); if (pkgBuf.charAt(0) != '/') pkgBuf.insert(0, '/'); final URL urlPath = ReflectUtils.class.getResource(pkgBuf.toString()); if (null == urlPath) return result; String checkedExtenion = extension; if (!extenion.endsWith(".class")) checkedExtenion = extension + ".class"; if (pkgBuf.toString().endsWith(".class"))) pkgBuf.delete(pkgBuf.lastIndexOf("/"), pkgBuf.length()); pkgBuf.deleteCharAt(0); final StringBuffer fileUrl = new StringBuffer(); try { fileUrl.append(URLDecoder.decode(urlPath.toExternalForm(), "UTF-8")); } catch (final UnsupportedEncodingException e1) { fileUrl.append(urlPath.toExternalForm()); } if (fileUrl.toString().startsWith("file:")) { fileUrl.delete(0, 5);// delete file: flag if (fileUrl.indexOf(":") != -1) fileUrl.deleteCharAt(0);// delete flag final String baseDir = fileUrl.substring(0, fileUrl.lastIndexOf("classes") + 8); ReflectUtils.doListNameOfPackageInDirectory(new File(baseDir), new File(baseDir), result, pkgBuf.toString(), checkedExtenion, fullPkgName); } else { ReflectUtils.doListNameOfPackageInJar(urlPath, urlPath, result, pkgBuf.toString(), checkedExtenion, fullPkgName); } return result; } /** */ private static void doListNameOfPackageInJar(final URL baseUrl, final URL urlPath, final List<String> result, final String clazzPkg, final String extension, final boolean fullPkgName) { try { // It does not work with the filesystem: we must // be in the case of a package contained in a jar file. final JarURLConnection conn = (JarURLConnection) urlPath.openConnection(); final JarFile jfile = conn.getJarFile(); final Enumeration<JarEntry> e = jfile.entries(); ZipEntry entry; String entryname; 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 (final IOException ioex) { } } private static void doListNameOfPackageInDirectory(final File baseDirectory, final File directory, final List<String> result, final String clazzPkg, final String extension, final boolean fullPkgName) { File[] files = directory.listFiles(); if (null == files) files = new File[] {}; String clazzPath; final int baseDirLen = baseDirectory.getAbsolutePath().length() + 1; for (final File file : files) { if (file.isDirectory()) { ReflectUtils.doListNameOfPackageInDirectory(baseDirectory, file, result, clazzPkg, extension, 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)); } } } } public static final <T> T initClass(final String implClass, final Class<T> tType) { return ReflectUtils.initClass(implClass, tType, true); } public static final <T> T initClass(final String implClass, final Class<T> tType, final boolean doInit) { try { final Object object = Class.forName(implClass, doInit, Thread.currentThread().getContextClassLoader()).newInstance(); return tType.cast(object); } catch (final Throwable e) { return null; } }}
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.