All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tinygroup.commons.tools.ClassLoaderUtil Maven / Gradle / Ivy

There is a newer version: 2.2.3
Show newest version
/**
 *  Copyright (c) 1997-2013, www.tinygroup.org ([email protected]).
 *
 *  Licensed under the GPL, Version 3.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.gnu.org/licenses/gpl.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.tinygroup.commons.tools;

import org.tinygroup.commons.exceptions.ClassInstantiationException;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static org.tinygroup.commons.tools.CollectionUtil.createHashSet;
import static org.tinygroup.commons.tools.CollectionUtil.createLinkedList;

/**
 * 

* 查找并装入类和资源的辅助类。 *

*

* ClassLoaderUtil查找类和资源的效果, 相当于ClassLoader.loadClass * 方法和ClassLoader.getResource方法。 但ClassLoaderUtil * 总是首先尝试从Thread.getContextClassLoader()方法取得 * ClassLoader中并装入类和资源。 这种方法避免了在多级ClassLoader * 的情况下,找不到类或资源的情况。 *

*

* 假设有如下情况: *

*
    *
  • 工具类A是从系统ClassLoader装入的(classpath)
  • *
  • B是Web Application中的一个类,是由servlet引擎的ClassLoader * 动态装入的
  • *
  • 资源文件C.properties也在Web Application中,只有servlet引擎的动态 * ClassLoader可以找到它
  • *
  • B调用工具类A的方法,希望通过类A取得资源文件 * C.properties
  • *
*

* 如果类A使用 * getClass().getClassLoader().getResource("C.properties") * , 就会失败,因为系统ClassLoader不能找到此资源。 * 但类A可以使用ClassLoaderUtil.getResource("C.properties"),就可以找到这个资源, * 因为ClassLoaderUtil调用Thread.currentThead().getContextClassLoader() * 取得了servlet引擎的ClassLoader, 从而找到了这个资源文件。 *

* * @author renhui */ public class ClassLoaderUtil { // ========================================================================== // 取得context class loader的方法。 // ========================================================================== /** * 取得当前线程的ClassLoader。这个功能需要JDK1.2或更高版本的JDK的支持。 * * @return 当前线程的ClassLoader */ public static ClassLoader getContextClassLoader() { return Thread.currentThread().getContextClassLoader(); } // ========================================================================== // 装入类的方法。 // ========================================================================== /** * 从当前线程的ClassLoader装入类。对于JDK1.2以下,则相当于 * Class.forName。 * * @param className 要装入的类名 * @return 已装入的类 * @throws ClassNotFoundException 如果类没找到 */ public static Class loadClass(String className) throws ClassNotFoundException { return loadClass(className, getContextClassLoader()); } /** * 从指定的调用者的ClassLoader装入类。 * * @param className 要装入的类名 * @param referrer 调用者类,如果为null,则该方法相当于 * Class.forName * @return 已装入的类 * @throws ClassNotFoundException 如果类没找到 */ public static Class loadClass(String className, Class referrer) throws ClassNotFoundException { ClassLoader classLoader = getReferrerClassLoader(referrer); // 如果classLoader为null,表示从ClassLoaderUtil所在的classloader中装载, // 这个classloader未必是System class loader。 return loadClass(className, classLoader); } /** * 从指定的ClassLoader中装入类。如果未指定ClassLoader, 则从装载 * ClassLoaderUtilClassLoader中装入。 * * @param className 要装入的类名 * @param classLoader 从指定的ClassLoader中装入类,如果为null * ,表示从ClassLoaderUtil所在的class loader中装载 * @return 已装入的类 * @throws ClassNotFoundException 如果类没找到 */ public static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { if (className == null) { return null; } if (classLoader == null) { return Class.forName(className); } else { return Class.forName(className, true, classLoader); } } /** * 取得调用者的class loader。 * * @param referrer 调用者类 * @return 调用者的class loader,如果referrer为null,则返回 * null */ private static ClassLoader getReferrerClassLoader(Class referrer) { ClassLoader classLoader = null; if (referrer != null) { classLoader = referrer.getClassLoader(); // classLoader为null,说明referrer类是由bootstrap classloader装载的, // 例如:java.lang.String if (classLoader == null) { classLoader = ClassLoader.getSystemClassLoader(); } } return classLoader; } // ========================================================================== // 装入并实例化类的方法。 // ========================================================================== /** * 从当前线程的ClassLoader装入类并实例化之。 * * @param className 要实例化的类名 * @return 指定类名的实例 * @throws ClassNotFoundException 如果类没找到 * @throws ClassInstantiationException 如果实例化失败 */ public static Object newInstance(String className) throws ClassNotFoundException, ClassInstantiationException { return newInstance(loadClass(className)); } /** * 从指定的调用者的ClassLoader装入类并实例化之。 * * @param className 要实例化的类名 * @param referrer 调用者类,如果为null,则从ClassLoaderUtil * 所在的class loader装载 * @return 指定类名的实例 * @throws ClassNotFoundException 如果类没找到 * @throws ClassInstantiationException 如果实例化失败 */ public static Object newInstance(String className, Class referrer) throws ClassNotFoundException, ClassInstantiationException { return newInstance(loadClass(className, referrer)); } /** * 从指定的ClassLoader中装入类并实例化之。如果未指定ClassLoader, 则从装载 * ClassLoaderUtilClassLoader中装入。 * * @param className 要实例化的类名 * @param classLoader 从指定的ClassLoader中装入类,如果为null * ,表示从ClassLoaderUtil所在的class loader中装载 * @return 指定类名的实例 * @throws ClassNotFoundException 如果类没找到 * @throws ClassInstantiationException 如果实例化失败 */ public static Object newInstance(String className, ClassLoader classLoader) throws ClassNotFoundException, ClassInstantiationException { return newInstance(loadClass(className, classLoader)); } /** * 创建指定类的实例。 * * @param clazz 要创建实例的类 * @return 指定类的实例 * @throws ClassInstantiationException 如果实例化失败 */ private static Object newInstance(Class clazz) throws ClassInstantiationException { if (clazz == null) { return null; } try { return clazz.newInstance(); } catch (InstantiationException e) { throw new ClassInstantiationException("Failed to instantiate class: " + clazz.getName(), e); } catch (IllegalAccessException e) { throw new ClassInstantiationException("Failed to instantiate class: " + clazz.getName(), e); } catch (Exception e) { throw new ClassInstantiationException("Failed to instantiate class: " + clazz.getName(), e); } } // ========================================================================== // 装入和查找资源文件的方法。 // ========================================================================== /** * 从ClassLoader取得所有resource URL。按如下顺序查找: *
    *
  1. 在当前线程的ClassLoader中查找。
  2. *
  3. 在装入自己的ClassLoader中查找。
  4. *
  5. 通过ClassLoader.getSystemResource方法查找。
  6. *
* * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @return resource的URL数组,如果没找到,则返回空数组。数组中保证不包含重复的URL。 */ public static URL[] getResources(String resourceName) { List urls = createLinkedList(); boolean found = false; // 首先试着从当前线程的ClassLoader中查找。 found = getResources(urls, resourceName, getContextClassLoader(), false); // 如果没找到,试着从装入自己的ClassLoader中查找。 if (!found) { found = getResources(urls, resourceName, ClassLoaderUtil.class.getClassLoader(), false); } // 最后的尝试: 在系统ClassLoader中查找(JDK1.2以上), // 或者在JDK的内部ClassLoader中查找(JDK1.2以下)。 if (!found) { found = getResources(urls, resourceName, null, true); } // 返回不重复的列表。 return getDistinctURLs(urls); } /** * 从指定调用者所属的ClassLoader取得所有resource URL。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @param referrer 调用者类,如果为null,表示在ClassLoaderUtil * 的class loader中找 * @return resource的URL数组,如果没找到,则返回空数组。数组中保证不包含重复的URL。 */ public static URL[] getResources(String resourceName, Class referrer) { ClassLoader classLoader = getReferrerClassLoader(referrer); List urls = createLinkedList(); getResources(urls, resourceName, classLoader, classLoader == null); // 返回不重复的列表。 return getDistinctURLs(urls); } /** * 从指定的ClassLoader中取得所有resource URL。如果未指定 * ClassLoader, 则从装载ClassLoaderUtil的 * ClassLoader中取得所有resource URL。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @param classLoader 从指定的ClassLoader中查找 * @return resource的URL数组,如果没找到,则返回空数组。数组中保证不包含重复的URL。 */ public static URL[] getResources(String resourceName, ClassLoader classLoader) { List urls = createLinkedList(); getResources(urls, resourceName, classLoader, classLoader == null); // 返回不重复的列表。 return getDistinctURLs(urls); } /** * 在指定class loader中查找指定名称的resource,把所有找到的resource的URL放入指定的集合中。 * * @param urlSet 存放resource URL的集合 * @param resourceName 资源名 * @param classLoader 类装入器 * @param sysClassLoader 是否用system class loader装载资源 * @return 如果找到,则返回true */ private static boolean getResources(List urlSet, String resourceName, ClassLoader classLoader, boolean sysClassLoader) { if (resourceName == null) { return false; } Enumeration i = null; try { if (classLoader != null) { i = classLoader.getResources(resourceName); } else if (sysClassLoader) { i = ClassLoader.getSystemResources(resourceName); } } catch (IOException e) { } if (i != null && i.hasMoreElements()) { while (i.hasMoreElements()) { urlSet.add(i.nextElement()); } return true; } return false; } /** * 去除URL列表中的重复项。 * * @param urls URL列表 * @return 不重复的URL数组,如果urls为null,则返回空数组 */ private static URL[] getDistinctURLs(List urls) { if (urls == null || urls.size() == 0) { return new URL[0]; } Set urlSet = createHashSet(); for (Iterator i = urls.iterator(); i.hasNext(); ) { URL url = i.next(); if (urlSet.contains(url)) { i.remove(); } else { urlSet.add(url); } } return urls.toArray(new URL[urls.size()]); } /** *

* 从ClassLoader取得resource URL。按如下顺序查找: *

*
    *
  1. 在当前线程的ClassLoader中查找。
  2. *
  3. 在装入自己的ClassLoader中查找。
  4. *
  5. 通过ClassLoader.getSystemResource方法查找。
  6. *
* * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @return resource的URL */ public static URL getResource(String resourceName) { if (resourceName == null) { return null; } ClassLoader classLoader = null; URL url = null; // 首先试着从当前线程的ClassLoader中查找。 classLoader = getContextClassLoader(); if (classLoader != null) { url = classLoader.getResource(resourceName); if (url != null) { return url; } } // 如果没找到,试着从装入自己的ClassLoader中查找。 classLoader = ClassLoaderUtil.class.getClassLoader(); if (classLoader != null) { url = classLoader.getResource(resourceName); if (url != null) { return url; } } // 最后的尝试: 在系统ClassLoader中查找(JDK1.2以上), // 或者在JDK的内部ClassLoader中查找(JDK1.2以下)。 return ClassLoader.getSystemResource(resourceName); } /** * 从指定调用者所属的ClassLoader取得resource URL。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @param referrer 调用者类,如果为null,表示在ClassLoaderUtil * 的class loader中找。 * @return resource URL,如果没找到,则返回null */ public static URL getResource(String resourceName, Class referrer) { if (resourceName == null) { return null; } ClassLoader classLoader = getReferrerClassLoader(referrer); return classLoader == null ? ClassLoaderUtil.class.getClassLoader().getResource(resourceName) : classLoader .getResource(resourceName); } /** * 从指定的ClassLoader取得resource URL。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @param classLoader 在指定classLoader中查找,如果为null,表示在 * ClassLoaderUtil的class loader中找。 * @return resource URL,如果没找到,则返回null */ public static URL getResource(String resourceName, ClassLoader classLoader) { if (resourceName == null) { return null; } return classLoader == null ? ClassLoaderUtil.class.getClassLoader().getResource(resourceName) : classLoader .getResource(resourceName); } /** * 从ClassLoader取得resource的输入流。 相当于 * getResource(resourceName).openStream()。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @return resource的输入流 */ public static InputStream getResourceAsStream(String resourceName) { URL url = getResource(resourceName); try { if (url != null) { return url.openStream(); } } catch (IOException e) { // 打开URL失败。 } return null; } /** * 从ClassLoader取得resource的输入流。 相当于 * getResource(resourceName, * referrer).openStream()。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @param referrer 调用者类,如果为null,表示在ClassLoaderUtil * 的class loader中找。 * @return resource的输入流 */ public static InputStream getResourceAsStream(String resourceName, Class referrer) { URL url = getResource(resourceName, referrer); try { if (url != null) { return url.openStream(); } } catch (IOException e) { // 打开URL失败。 } return null; } /** * 从ClassLoader取得resource的输入流。 相当于 * getResource(resourceName, * classLoader).openStream()。 * * @param resourceName 要查找的资源名,就是以"/"分隔的标识符字符串 * @param classLoader 在指定classLoader中查找,如果为null,表示在 * ClassLoaderUtil的class loader中找。 * @return resource的输入流 */ public static InputStream getResourceAsStream(String resourceName, ClassLoader classLoader) { URL url = getResource(resourceName, classLoader); try { if (url != null) { return url.openStream(); } } catch (IOException e) { // 打开URL失败。 } return null; } // ========================================================================== // 查找class的位置。 // // 类似于UNIX的which方法。 // ========================================================================== /** * 从当前线程的ClassLoader中查找指定名称的类。 * * @param className 要查找的类名 * @return URL数组,列举了系统中所有可找到的同名类,如果未找到,则返回一个空数组 */ public static URL[] whichClasses(String className) { return getResources(ClassUtil.getResourceNameForClass(className)); } /** * 从当前线程的ClassLoader中查找指定名称的类。 * * @param className 要查找的类名 * @param referrer 调用者类,如果为null,表示在ClassLoaderUtil * 的class loader中找。 * @return URL数组,列举了系统中所有可找到的同名类,如果未找到,则返回一个空数组 */ public static URL[] whichClasses(String className, Class referrer) { return getResources(ClassUtil.getResourceNameForClass(className), referrer); } /** * 从当前线程的ClassLoader中查找指定名称的类。 * * @param className 要查找的类名 * @param classLoader 在指定classLoader中查找,如果为null,表示在 * ClassLoaderUtil的class loader中找。 * @return URL数组,列举了系统中所有可找到的同名类,如果未找到,则返回一个空数组 */ public static URL[] whichClasses(String className, ClassLoader classLoader) { return getResources(ClassUtil.getResourceNameForClass(className), classLoader); } /** * 从当前线程的ClassLoader中查找指定名称的类。 * * @param className 要查找的类名 * @return 类文件的URL,如果未找到,则返回null */ public static URL whichClass(String className) { return getResource(ClassUtil.getResourceNameForClass(className)); } /** * 从当前线程的ClassLoader中查找指定名称的类。 * * @param className 要查找的类名 * @param referrer 调用者类,如果为null,表示在ClassLoaderUtil * 的class loader中找。 * @return 类文件的URL,如果未找到,则返回null */ public static URL whichClass(String className, Class referrer) { return getResource(ClassUtil.getResourceNameForClass(className), referrer); } /** * 从当前线程的ClassLoader中查找指定名称的类。 * * @param className 要查找的类名 * @param classLoader 在指定classLoader中查找,如果为null,表示在 * ClassLoaderUtil的class loader中找。 * @return 类文件的URL,如果未找到,则返回null */ public static URL whichClass(String className, ClassLoader classLoader) { return getResource(ClassUtil.getResourceNameForClass(className), classLoader); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy