`

实现自定义的classLoader加载classpath中的class

    博客分类:
  • JAVA
 
阅读更多

转载:http://www.blogjava.net/shenh062326/archive/2012/05/20/378623.html

 

最近这些天学习了classLoader的原理, 原因是因为服务器上的一个java进程启动时加载两个不同版本的jar包, 含有相同名字的类, 而且服务端的jar包排在前面, 我上传的jar包排在后面, 于是每次都使用服务端的jar包, 我的jar包便无法生效, 因此希望修改classLader, 让它按相反的顺序加载jar包.
     网上查阅了classLoader的原理, 分析jvm默认使用AppClassLoader加载classpath中的类, 因此目标很明确, 替换它就行了, 找到一个参数

java.system.class.loader, 只需要在启动java进程的时候把它设置为自己的类就行. 
     开始写自己的classLoader, 参考URLClassLoader与网上的介绍, 写了一个简单的,上代码:
  1 package org.taobao.yuling.testClassLoader;
  2 
  3 import java.io.*;
  4 import java.lang.reflect.*;
  5 import java.net.MalformedURLException;
  6 import java.net.URL;
  7 import java.net.URLClassLoader;
  8 import java.nio.ByteBuffer;
  9 import java.security.AccessControlContext;
 10 import java.security.AccessController;
 11 import java.security.CodeSigner;
 12 import java.security.CodeSource;
 13 import java.security.PermissionCollection;
 14 import java.security.PrivilegedAction;
 15 import java.security.SecureClassLoader;
 16 import java.util.Arrays;
 17 import java.util.HashMap;
 18 import java.util.Map;
 19 import java.util.jar.Attributes;
 20 import java.util.jar.Manifest;
 21 
 22 
 23 import sun.misc.JavaNetAccess;
 24 import sun.misc.Resource;
 25 import sun.misc.SharedSecrets;
 26 import sun.misc.URLClassPath;
 27 
 28 /**
 29  * The class loader used for loading from java.class.path.
 30  * runs in a restricted security context.
 31  */
 32 public class MyClassLoader extends URLClassLoader {
 33     public URLClassPath ucp;
 34       private Map<String, Class<?>> cache = new HashMap();
 35       private static final Method defineClassNoVerifyMethod;
 36       
 37       static String[] paths = System.getProperty("java.class.path").split(";");
 38       
 39       static URL[] urls = new URL[paths.length];
 40 
 41       static{
 42           System.out.println(Arrays.toString(paths));
 43           System.out.println(System.getProperty("java.class.path"));
 44           for(int i=0; i<urls.length; i++){
 45               try {
 46                   
 47                 urls[i] = new URL("file:"+paths[paths.length-1-i]);
 48             } catch (MalformedURLException e) {
 49                 e.printStackTrace();
 50             }
 51           }
 52           System.out.println(Arrays.toString(urls));
 53         SharedSecrets.setJavaNetAccess(new JavaNetAccess() {
 54           public URLClassPath getURLClassPath(URLClassLoader u) {
 55             return ((MyClassLoader)u).ucp;
 56           } } );
 57         Method m;
 58         try {
 59           m = SecureClassLoader.class.getDeclaredMethod(
 60             "defineClassNoVerify", new Class[] { String.class
 61             ByteBuffer.class, CodeSource.class });
 62           m.setAccessible(true);
 63         } catch (NoSuchMethodException nsme) {
 64           m = null;
 65         }
 66         defineClassNoVerifyMethod = m;
 67       }
 68       
 69       public MyClassLoader(URL[] urls) {
 70             super(MyClassLoader.urls);
 71             this.ucp = new URLClassPath(MyClassLoader.urls);
 72         }
 73       
 74       public MyClassLoader(ClassLoader parent) {
 75             super(MyClassLoader.urls, parent);
 76             this.ucp = new URLClassPath(MyClassLoader.urls);
 77         }
 78 
 79       public Class<?> loadClass(String name)
 80         throws ClassNotFoundException{
 81         Class c = null;
 82         
 83         if (name.contains("hadoop")) {
 84           c = (Class)this.cache.get(name);
 85           if (c == null) {
 86             c = findClass(name);
 87             this.cache.put(name, c);
 88           }
 89         } else {
 90           c = loadClass(name, false);
 91         }
 92         return c;
 93       }
 94 
 95       protected Class<?> findClass(String name)
 96         throws ClassNotFoundException
 97       {
 98         String path = name.replace('.', '/').concat(".class");
 99         Resource res = this.ucp.getResource(path);
100         if (res != null) {
101           try {
102             return defineClass(name, res, true);
103           } catch (IOException e) {
104             throw new ClassNotFoundException(name, e);
105           }
106         }
107         throw new ClassNotFoundException(name);
108       }
109 
110       private Class<?> defineClass(String name, Resource res, boolean verify) throws IOException
111       {
112         int i = name.lastIndexOf('.');
113         URL url = res.getCodeSourceURL();
114         if (i != -1) {
115           String pkgname = name.substring(0, i);
116 
117           Package pkg = getPackage(pkgname);
118           Manifest man = res.getManifest();
119           if (pkg != null)
120           {
121             if (pkg.isSealed())
122             {
123               if (!pkg.isSealed(url)) {
124                 throw new SecurityException(
125                   "sealing violation: package " + pkgname + 
126                   " is sealed");
127               }
128 
129             }
130             else if ((man != null) && (isSealed(pkgname, man))) {
131               throw new SecurityException(
132                 "sealing violation: can't seal package " + 
133                 pkgname + ": already loaded");
134             }
135 
136           }
137           else if (man != null)
138             definePackage(pkgname, man, url);
139           else {
140             definePackage(pkgname, nullnullnullnullnullnull
141               null);
142           }
143 
144         }
145 
146         ByteBuffer bb = res.getByteBuffer();
147         byte[] bytes = bb == null ? res.getBytes() : null;
148 
149         CodeSigner[] signers = res.getCodeSigners();
150         CodeSource cs = new CodeSource(url, signers);
151 
152         if (!verify)
153         {
154           Object[] args = { name, bb == null ? ByteBuffer.wrap(bytes) : bb, 
155             cs };
156           try {
157             return (Class)defineClassNoVerifyMethod.invoke(this, args);
158           }
159           catch (IllegalAccessException localIllegalAccessException) {
160           }
161           catch (InvocationTargetException ite) {
162             Throwable te = ite.getTargetException();
163             if ((te instanceof LinkageError))
164               throw ((LinkageError)te);
165             if ((te instanceof RuntimeException)) {
166               throw ((RuntimeException)te);
167             }
168             throw new RuntimeException("Error defining class " + name, 
169               te);
170           }
171 
172         }
173         return defineClass(name, bytes, 0, bytes.length, cs);
174       }
175 
176       private boolean isSealed(String name, Manifest man) {
177         String path = name.replace('.', '/').concat("/");
178         Attributes attr = man.getAttributes(path);
179         String sealed = null;
180         if (attr != null) {
181           sealed = attr.getValue(Attributes.Name.SEALED);
182         }
183         if ((sealed == null) && 
184           ((attr = man.getMainAttributes()) != null)) {
185           sealed = attr.getValue(Attributes.Name.SEALED);
186         }
187 
188         return "true".equalsIgnoreCase(sealed);
189       }
190 }
191 
注: isSealed(), defineClass(), findClass(), 都是直接从URLClassLoader复制过来.
代码较粗糙, 不过意思很简单, 就是通过把java.class.path的jar包反顺序, 然后定义了自己的
Class<?> loadClass(String name) 方法, 在加载我需要的类时在已被反序的的jar包中查找, 这样就能首先加载我修改的类了. 
运行方法:
java -Djava.system.class.loader=org.taobao.yuling.testClassLoader.MyClassLoader -classpath ...  MyTestClass

 

分享到:
评论

相关推荐

    自定义classloader的使用

    自定义Classloader还可以实现动态加载和卸载类的功能。在某些场景下,比如插件系统,我们需要在运行时加载或卸载特定的类,这时自定义Classloader的灵活性就体现出来了。 七、安全考虑 尽管自定义Classloader提供...

    java自定义类加载classloader文档,包括代码

    2. **Extension Class Loader(扩展类加载器)**:该类加载器由`sun.misc.Launcher$ExtClassLoader`实现,负责加载`JAVA_HOME/jre/lib/ext`目录中的所有类库。Extension Class Loader的父加载器为Bootstrap Class ...

    ClassLoader类加载器

    自定义ClassLoader通常是为了满足特定的加载需求,例如从网络、数据库或非标准路径加载类。下面是一个简单的自定义ClassLoader的示例: ```java public class MyClassLoader extends ClassLoader { private String...

    定义ClassLoader调用外部jar包

    默认情况下,Java使用系统ClassLoader(Bootstrap ClassLoader)加载JDK核心库,然后是Extension ClassLoader加载扩展库,最后是App ClassLoader加载应用类路径(ClassPath)下的类。当这些默认ClassLoader无法满足...

    自定义类加载器

    Java中的类加载器通常形成一个树状的层次结构,其中Bootstrap ClassLoader是最顶层的加载器,由JVM自身实现,主要负责加载`&lt;JAVA_HOME&gt;/lib`目录下的核心类库。接下来是Extension ClassLoader,它加载`&lt;JAVA_HOME&gt;/...

    ClassLoader运行机制 自己写的

    这里我们将详细讨论ClassLoader的运行机制,特别是自定义ClassLoader的设计与实现。 ClassLoader的基本职责是根据类名动态加载对应的类文件。在Java中,类加载过程遵循双亲委派模型(Parent Delegation Model)。这...

    class文件热加载,上传class文件实现热加载

    - Bootstrap ClassLoader加载JDK核心库(rt.jar),Extension ClassLoader加载JRE扩展目录下的jar,AppClassLoader加载应用的类路径(classpath)中的类。 2. **自定义类加载器**: - 开发者可以创建自定义类加载...

    自定义Java类加载器

    总的来说,自定义Java类加载器是深入理解和控制JVM行为的重要手段,它可以让我们在程序设计中实现更高级别的灵活性和定制性。通过`MyClassLoader`,你可以按照个人需求来调整类的加载策略,进一步提升软件系统的功能...

    classloader 加密解密应用程序 ,反编译class

    Bootstrap ClassLoader加载JRE的核心库,Extension ClassLoader加载Java扩展目录下的类,而AppClassLoader则加载应用的主类路径(ClassPath)上的类。 接下来,我们来讨论“加密解密应用程序”。在Java环境中,为了...

    classloader

    3. 整合自定义ClassLoader:了解如何将自定义的ClassLoader集成到Java应用程序中,替换或扩展默认的加载行为。 4. 考虑Java 2版本的兼容性:学习如何修改你的ClassLoader以适应Java 2及以上版本的特性,比如支持...

    Java ClassLoader学习总结

    在加载流程中,当运行一个程序的时候,JVM 首先启动 bootstrap classloader,该 ClassLoader 加载 Java 核心 API,然后调用 ExtClassLoader 加载扩展 API,最后 AppClassLoader 加载 CLASSPATH 目录下定义的 Class,...

    Java类动态加载(一)——java源文件动态编译为class文件

    通过自定义ClassLoader和利用`JavaCompiler` API,我们可以实现Java源文件的动态编译和加载,从而实现程序运行时的灵活扩展。在实际应用中,我们需要注意类加载的性能影响,以及类加载器之间的隔离问题,以确保系统...

    ClassLoader 详解.doc

    自定义ClassLoader通常需要重写findClass()或loadClass()方法,以控制类的加载行为。 理解ClassLoader的工作原理对于排查类冲突、处理依赖关系以及优化大型J2EE应用的性能具有重要意义。开发者可以通过日志输出、...

    JVM ClassLoader简析

    这些代码可能展示了如何创建自定义ClassLoader,以及如何使用ClassLoader加载非标准位置的类。通过分析这些示例,我们可以更好地理解ClassLoader的工作机制。 总的来说,理解和掌握JVM ClassLoader对于优化Java应用...

    了解Java ClassLoader

    下面将详细介绍Java ClassLoader的基本概念、工作流程、类加载机制以及自定义ClassLoader。 1. **ClassLoader基本概念** - ClassLoader是一个Java类,用于动态加载Java类到JVM中。Java程序中的每个类都由某个...

    ClassLoader的 一些测试

    4. 类隔离:通过自定义ClassLoader实现不同模块之间的类隔离,避免类冲突。 总的来说,深入理解ClassLoader的工作原理对于优化程序性能、构建灵活的插件系统和解决类冲突问题具有重要意义。通过测试和实践,我们...

    理解Java ClassLoader机制

    最后,App ClassLoader加载的是应用类路径(ClassPath)中的类。 ClassLoader的工作流程主要包含以下步骤: 1. **查找类**:当JVM需要加载一个类时,ClassLoader会根据类名(全限定名,如`java.lang.String`)在...

    Java类加载器(ClassLoader)1

    - 实现自定义类加载器时,建议在JDK1.2后重写findClass()方法而非loadClass(),以避免复杂的操作。 **常用方法**: - `getParent()`:返回当前类加载器的父类加载器。 - `forName(String className)`:根据类名动态...

    ClassLoader总结

    开发者可以继承ClassLoader并重写其loadClass方法,以实现自定义的加载逻辑,例如从数据库或网络中加载类。 在实际开发中,自定义ClassLoader有多种应用场景。例如,在模块化开发中,每个模块可能有自己的...

    关于java热部署知识.doc

    // 使用自定义ClassLoader加载新版本的类 c = dc.findClass(classBytes); } return c; } private boolean isClassModified(String className) { // 检查类文件的修改时间 } private byte[] readClassFile...

Global site tag (gtag.js) - Google Analytics