Java tutorial
/* * Copyright (C) 2008 feilong * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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 com.feilong.core.lang; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.feilong.core.UncheckedIOException; import com.feilong.tools.jsonlib.JsonUtil; import com.feilong.tools.slf4j.Slf4jUtil; import static com.feilong.core.bean.ConvertUtil.toList; /** * {@link java.lang.ClassLoader ClassLoader}. * * <h3>?:</h3> * * <blockquote> * * <ul> * <li>{@link #getResource(String)}</li> * <li>{@link #getResourceInAllClassLoader(String, Class)}</li> * </ul> * </blockquote> * * <h3> {@link java.lang.Class#getResourceAsStream(String) Class#getResourceAsStream(String)} VS * {@link java.lang.ClassLoader#getResourceAsStream(String) ClassLoader#getResourceAsStream(String)}</h3> * * <blockquote> * <p> * ,? classpath ???,classpath?classpathclasspathjar * </p> * <p> * ?? src/main/resources?, messages/feilong-core-message_en_US.properties, * </p> * <ol> * <li>{@link java.lang.Class#getResourceAsStream(String) Class#getResourceAsStream(String)} ? * <b>"/messages/feilong-core-message_en_US.properties"</b>,<br> * ???; / ,?, ? / , class</li> * <li>{@link java.lang.ClassLoader#getResourceAsStream(String) ClassLoader#getResourceAsStream(String)} ? * <b>"messages/feilong-core-message_en_US.properties"</b>,<br> * {@link ClassLoader} JVMBootstrapLoader?.<br> * ??"messages/feilong-core-message_en_US.properties" <span style="color:red">??"/"</span></li> * <li>spring,???, <code>org.springframework.core.io.ClassPathResource</code>,{@link ClassLoader},? * <code>org.springframework.util.StringUtils#cleanPath(String)</code>,?/?, ,?</li> * </ol> * * </blockquote> * * @author <a href="http://feitianbenyue.iteye.com/">feilong</a> * @see java.lang.ClassLoader * @see java.net.URLClassLoader * @see "org.springframework.core.io.ClassPathResource#ClassPathResource(String, ClassLoader)" * @since 1.0.0 */ public final class ClassLoaderUtil { /** The Constant LOGGER. */ private static final Logger LOGGER = LoggerFactory.getLogger(ClassLoaderUtil.class); /** Don't let anyone instantiate this class. */ private ClassLoaderUtil() { //AssertionError?. ?????. ???. //see Effective Java 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } /** * ???,?????????. * * <h3>:</h3> * * <blockquote> * * <p> * ,<code> src/test/resources</code> ? <code>messages/feilong-core-test.properties</code> ?,?,? * <code>target/test-classes/messages/feilong-core-test.properties</code> * </p> * * <pre class="code"> * ClassLoaderUtil.getResource("/messages/feilong-core-test.properties") * ClassLoaderUtil.getResource("messages/feilong-core-test.properties") * </pre> * * ? * * <pre class="code"> * file:/E:/Workspaces/feilong/feilong-core/target/test-classes/messages/feilong-core-test.properties * </pre> * * </blockquote> * * <h3>?:</h3> * <blockquote> * <ol> * <li> <code>resourceName</code> ? "/" ,?, ClassLoader?????, ?? * <code>org.springframework.core.io.ClassPathResource#ClassPathResource(String, ClassLoader)</code></li> * <li>"",classes </li> * </ol> * </blockquote> * * <h3>???:</h3> * * <blockquote> * <table border="1" cellspacing="0" cellpadding="4" summary=""> * <tr style="background-color:#ccccff"> * <th align="left"></th> * <th align="left">(maven)</th> * <th align="left">web,(??jar)</th> * </tr> * <tr valign="top"> * <td><code>getResource("")</code></td> * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-core/target/test-classes/</td> * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-web-test/src/main/webapp/WEB-INF/classes/</td> * </tr> * <tr valign="top" style="background-color:#eeeeff"> * <td><code>getResource("com")</code></td> * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-core/target/test-classes/com</td> * <td>file:/E:/Workspaces/feilong/feilong-platform/feilong-web-test/src/main/webapp/WEB-INF/classes/com/</td> * </tr> * </table> * </blockquote> * * @param resourceName * the resource name * @return <code>resourceName</code> null, {@link NullPointerException}<br> * ??,????, null * @see org.apache.commons.lang3.ClassPathUtils#toFullyQualifiedPath(Package, String) * @see #getResource(ClassLoader, String) * @see #getClassLoaderByClass(Class) */ public static URL getResource(String resourceName) { return getResource(getClassLoaderByClass(ClassLoaderUtil.class), resourceName); } /** * ???,?????????. * * <h3>?:</h3> * <blockquote> * <ol> * <li> <code>resourceName</code> ? "/" ,?, ClassLoader???? ?, ?? * <code>org.springframework.core.io.ClassPathResource#ClassPathResource(String, ClassLoader)</code></li> * <li>"",classes </li> * </ol> * </blockquote> * * @param classLoader * the class loader * @param resourceName * the resource name * @return <code>classLoader</code> null, {@link NullPointerException}<br> * <code>resourceName</code> null, {@link NullPointerException}<br> * ??,????, null * @since 1.2.1 */ private static URL getResource(ClassLoader classLoader, String resourceName) { Validate.notNull(classLoader, "classLoader can't be null!"); Validate.notNull(resourceName, "resourceName can't be null!"); boolean startsWithSlash = resourceName.startsWith("/"); String usePath = startsWithSlash ? StringUtil.substring(resourceName, 1) : resourceName; URL result = classLoader.getResource(usePath); LOGGER.info("search resource:[\"{}\"] in [{}],result:[{}]", resourceName, classLoader, result); return result; } // ***************************************************** /** * This is a convenience method to load a resource as a stream. * * <h3>?:</h3> * <blockquote> * <ol> * <li> <code>resourceName</code> ? "/" ,?, ClassLoader???? ?, ?? * <code>org.springframework.core.io.ClassPathResource#ClassPathResource(String, ClassLoader)</code></li> * <li>"",classes </li> * </ol> * </blockquote> * * @param resourceName * The name of the resource to load * @param callingClass * The Class object of the calling object * @return <code>resourceName</code> null, {@link NullPointerException}<br> * ??, null * @see #getResourceInAllClassLoader(String, Class) * @see "org.apache.velocity.util.ClassUtils#getResourceAsStream(Class, String)" */ public static InputStream getResourceAsStream(String resourceName, Class<?> callingClass) { URL url = getResourceInAllClassLoader(resourceName, callingClass); try { return url == null ? null : url.openStream(); } catch (IOException e) { String message = Slf4jUtil.format("can not open resourceName:[{}]", resourceName); LOGGER.error(message, e); throw new UncheckedIOException(message, e); } } /** * Load a given resource. * * <h3>?:</h3> * <blockquote> * <ol> * <li> <code>resourceName</code> ? "/" ,?, ClassLoader???? ?, ?? * <code>org.springframework.core.io.ClassPathResource#ClassPathResource(String, ClassLoader)</code></li> * <li>"",classes </li> * </ol> * </blockquote> * * <p> * This method will try to load the resource using the following methods (in order): * </p> * <ul> * <li>From {@link Thread#getContextClassLoader() Thread.currentThread().getContextClassLoader()} * <li>From {@link Class#getClassLoader() ClassLoaderUtil.class.getClassLoader()} * <li>From {@link Class#getClassLoader() callingClass.getClassLoader() } * </ul> * * @param resourceName * The name of the resource to load * @param callingClass * The Class object of the calling object * @return <code>resourceName</code> null, {@link NullPointerException}<br> * {@link ClassLoader}???,null * @since 1.6.2 */ public static URL getResourceInAllClassLoader(String resourceName, Class<?> callingClass) { List<ClassLoader> classLoaderList = getAllClassLoaderList(callingClass); for (ClassLoader classLoader : classLoaderList) { if (null == classLoader) { continue; } URL url = getResource(classLoader, resourceName); if (null == url) { LOGGER.warn(getLogInfo(resourceName, classLoader, false)); } else { if (LOGGER.isTraceEnabled()) { LOGGER.trace(getLogInfo(resourceName, classLoader, true)); } return url; } } LOGGER.warn("not found:[{}] in all ClassLoader,return null", resourceName); return null; } //************************************************************************************************** /** * all class loader list. * * @param callingClass * the calling class * @return the all class loader * @since 1.6.2 */ private static List<ClassLoader> getAllClassLoaderList(Class<?> callingClass) { return toList(getClassLoaderByCurrentThread(), getClassLoaderByClass(ClassLoaderUtil.class), null == callingClass ? null : getClassLoaderByClass(callingClass)); } /** * {@link Thread#getContextClassLoader()} {@link ClassLoader}. * * @return the class loader by current thread */ private static ClassLoader getClassLoaderByCurrentThread() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("[Thread.currentThread()].getContextClassLoader:{}", formatClassLoader(classLoader)); } return classLoader; } /** * ? {@link ClassLoader}. * * @param callingClass * the calling class * @return <code>callingClass</code> null, {@link NullPointerException}<br> * @see java.lang.Class#getClassLoader() */ private static ClassLoader getClassLoaderByClass(Class<?> callingClass) { Validate.notNull(callingClass, "callingClass can't be null!"); ClassLoader classLoader = callingClass.getClassLoader(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("[{}].getClassLoader():{}", callingClass.getSimpleName(), formatClassLoader(classLoader)); } return classLoader; } /** * log info. * * @param resourceName * the resource name * @param classLoader * the class loader * @param isFouned * the is founed * @return the log info * @since 1.6.2 */ private static String getLogInfo(String resourceName, ClassLoader classLoader, boolean isFouned) { String message = "{}found [{}],in ClassLoader:[{}]"; return Slf4jUtil.format(message, isFouned ? "" : "not ", resourceName, formatClassLoader(classLoader)); } /** * Format class loader. * * @param classLoader * the class loader * @return the string * @since 1.6.2 */ private static String formatClassLoader(ClassLoader classLoader) { Map<String, Object> map = new LinkedHashMap<String, Object>(); map.put("classLoader", "" + classLoader); map.put("classLoader[CanonicalName]", classLoader.getClass().getCanonicalName()); map.put("classLoader[Root Classpath]", "" + getRootClassPath(classLoader)); return JsonUtil.format(map); } /** * class path. * * @param classLoader * the class loader * @return <code>classLoader</code> null, {@link NullPointerException}<br> * @see #getResource(ClassLoader, String) * @since 1.6.2 */ private static URL getRootClassPath(ClassLoader classLoader) { Validate.notNull(classLoader, "classLoader can't be null!"); return getResource(classLoader, ""); } }