精华内容
下载资源
问答
  • java 自定义classloader

    2019-02-12 09:58:51
    java中默认提供了三类classloader,分别加载不同目录下的class或者jar包,...这个时候,默认的classloader就不能满足要求了,需要自定义classloader 自定义classloader很简单, (1)继承java.lang.ClassLoader...

    java中默认提供了三类classloader,分别加载不同目录下的class或者jar包,如果有一些非通用的需求,比如想从一个特定的位置加载class,如http地址、网盘、U盘等;又比如想对class做一些隔离;这个时候,默认的classloader就不能满足要求了,需要自定义classloader

    自定义classloader很简单,

    (1)继承java.lang.ClassLoader

    (2)重写父类相关的方法

    先看下ClassLoader的相关代码,java.lang.ClassLoader#loadClass(java.lang.String, boolean)

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
    
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);
    
                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

    可以看到,jvm是根据一定的顺序来查找特定的class,如果父类或者bootstrapclassloader找不到,最终会调用findClass来加载指定的class,所以,只需重写该方法即可

    网上的实例代码:https://blog.csdn.net/xyang81/article/details/7292380

    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.net.URL;
    
    /**
     * 加载网络class的ClassLoader
     */
    public class NetworkClassLoader extends ClassLoader {
    
        private String rootUrl;
    
        public NetworkClassLoader(String rootUrl) {
            this.rootUrl = rootUrl;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            Class clazz;
            //根据类的二进制名称,获得该class文件的字节码数组
            byte[] classData = getClassData(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            }
            //将class的字节码数组转换成Class类的实例
            clazz = defineClass(name, classData, 0, classData.length); 
            return clazz;
        }
    
        private byte[] getClassData(String name) {
            InputStream is = null;
            try {
                String path = classNameToPath(name);
                URL url = new URL(path);
                byte[] buff = new byte[1024*4];
                int len = -1;
                is = url.openStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                while((len = is.read(buff)) != -1) {
                    baos.write(buff,0,len);
                }
                return baos.toByteArray();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch(Exception e) {
                    }
                }
            }
            return null;
        }
    
        private String classNameToPath(String name) {
            return rootUrl + "/" + name.replace(".", "/") + ".class";
        }
    
    }

     

    展开全文
  • Java自定义ClassLoader加载Class的问题前面两篇介绍了Java中的ClassLoader,如果对ClassLoader不熟悉的朋友可以参考以下文章。Java中的ClassLoader机制Java自定义ClassLoader实现在自定义ClassLoader的时候,我们不...

    c6f704a69e16f502faadaa17351aefd1.png

    45931dca9aca3e82f19b172e1dff79e3.png


    Java自定义ClassLoader加载Class的问题
    前面两篇介绍了Java中的ClassLoader,如果对ClassLoader不熟悉的朋友可以参考以下文章。
    Java中的ClassLoader机制
    Java自定义ClassLoader实现
    在自定义ClassLoader的时候,我们不能把加载进来的class直接转成对应的对象,因为这两是不同classLoader加载进来的,下面是测试的代码,T2是一个自定义的类,里面有个getMsg的方法,getMsg方法返回一个固定的字符串。用自定义ClassLoader(上文有源码)加载的class的实例直接强制转成T2,我们运行下面的代码,可以看看结果。

    864cd12de7ef438e5657190aa79b1a8a.png


    测试1代码
    上面的代码执行结果如下:Exception in thread "main" java.lang.ClassCastException: test.T2 cannot be cast to test.T2at test.Test1.main(Test1.java:13)
    可见发生了ClassCastException异常,原因就是T2是AppClassLoader加载的,aClass1是用我们自定义的ClassLoader加载的,所有不能直接转换。如果想要调用T2的getMsg方法,我们可以用反射方式。下面的就是用反射实现的代码。
    Method method = aClass1.getDeclaredMethod("getMsg"); method.invoke(aClass1.newInstance(),new Object[]{});如果我们想直接转成T2呢?
    就需要把T2的加载也是我们自定义的ClassLoader来加载,我们可以创建一个类,这个类用自定义ClassLoader加载,里面的T2也会用我们的ClassLoader加载,这样就可以强制转换,源码如下:

    c3d5a9b7e0b5b02fa3585e7a32e30dec.png


    Test2测试类
    我们写个Main方法来加载Test2,步骤如下

    • 初始化自定义ClassLoader
    • 用自定义ClassLoader来加载Test2
    • 用放射机制来调用Test2的test方法

    3952f05ed2569d99aebfe03e04c1f7ca.png


    测试启动类
    测试正常结束,并且打印出的结果看T2是我们自定义的ClassLoader加载的,这样强制转换就不会发生异常。

    6905b86c6f7d84031e5678f59167d141.png


    测试结果
    最后附上T2的定义

    484f20aa3bf8e210c7be03d00b45c0c5.png


    T2

    展开全文
  • 继承ClassLoader并且重写findClass方法就可以自定义一个类加载器,具体什么是类加载器以及类加载器的加载过程与顺序下次再说,下面给出一个小demo首先定义一个类,比如MyTest,并且将其编译成class文件,然后放到一...

    继承ClassLoader并且重写findClass方法就可以自定义一个类加载器,具体什么是类加载器以及类加载器的加载过程与顺序下次再说,下面给出一个小demo

    首先定义一个类,比如MyTest,并且将其编译成class文件,然后放到一个指定的文件夹下面,其中文件夹的最后几层就是它的包名,这里我将这个编译好的类放到 : /Users/allen/Desktop/cn/lijie/MyTest.class

    ab92dfaee27a2a47b38c36344f77c1b4.png

    package cn.lijie;

    public class MyTest {

    public void show() {

    System.out.println("show test!");

    }

    }

    自定义的类加载器:

    public class MyClassLoader extends ClassLoader {

    @Override

    protected Class> findClass(String name) {

    String myPath = "file:///Users/allen/Desktop/" + name.replace(".","/") + ".class";

    System.out.println(myPath);

    byte[] cLassBytes = null;

    Path path = null;

    try {

    path = Paths.get(new URI(myPath));

    cLassBytes = Files.readAllBytes(path);

    } catch (IOException | URISyntaxException e) {

    e.printStackTrace();

    }

    Class clazz = defineClass(name, cLassBytes, 0, cLassBytes.length);

    return clazz;

    }

    }

    测试的主函数:

    public class MainClass {

    public static void main(String[] args) throws ClassNotFoundException {

    MyClassLoader loader = new MyClassLoader();

    Class> aClass = loader.findClass("cn.lijie.MyTest");

    try {

    Object obj = aClass.newInstance();

    Method method = aClass.getMethod("show");

    method.invoke(obj);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    执行主函数,调用外部class的show方法:

    b0d38c965fce30b5a464133e8625c98c.png

    补充:java远程加载class文件

    1.在win上创建java文件并编译

    e0fc74242c39d27188aa521997d266b5.png

    2.上传到远程服务器

    b537d0cf324ea0f752337c50a4541afd.png

    3.编写java代码

    准备:

    引入jar包 ganymed-ssh2-262.jar

    1.加载外部class要定义自己的类加载器

    2.使用内存流

    import java.io.ByteArrayOutputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import ch.ethz.ssh2.Connection;

    import ch.ethz.ssh2.SFTPInputStream;

    import ch.ethz.ssh2.SFTPv3Client;

    public class Fs{

    public static void main(String[] args) throws Exception {

    OwnClassLoader ocl = new OwnClassLoader();

    String ip,user,password;

    ip = "120.34.168.80";//自己的远程ip

    user = "root";//username

    password = "123456";//password

    ocl.login(ip, user, password);

    Object obj = ocl.loadeOthClass("/opt/4/tt.class");//class文件路径

    System.out.println(obj);

    Class c = obj.getClass();

    Field f = c.getDeclaredField("age");

    f.setAccessible(true);

    System.out.println("age:"+f.get(obj));

    }

    }

    //自定义类加载器

    class OwnClassLoader extends ClassLoader{

    private Connection conn = null;

    //初始化链接

    public Connection login(String ip,String user,String password){

    Connection conn = null;

    try {

    //也可以new Connection(ip, port)创建对象,默认22

    conn = new Connection(ip);

    //连接远程服务

    conn.connect();

    //使用用户名和密码登录

    conn.authenticateWithPassword(user, password);

    this.conn = conn;

    return conn;

    } catch (IOException e) {

    e.printStackTrace();

    }

    return null;

    }

    //返回远程实例

    public Object loadeOthClass(String url) throws Exception{

    if(null==conn)

    throw new Exception("请初始化链接");

    SFTPv3Client sc = new SFTPv3Client(conn);//创建ssh客户端连接

    InputStream is = new SFTPInputStream(sc.openFileRO(url));//创建输入流

    byte[] b = this.readClassFile(is);

    Class> c = super.defineClass(b, 0, b.length);//定义class

    return c.newInstance();//创建实例

    }

    //读取远程class文件

    private byte[] readClassFile(InputStream is){

    byte[] b = new byte[1024];

    int len;

    ByteArrayOutputStream bos = null;

    try {

    bos = new ByteArrayOutputStream();//内存流输出

    while((len=is.read(b))!=-1){

    bos.write(b, 0, len);

    }

    b = bos.toByteArray();

    } catch (Exception e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }finally{

    try {

    if(is!=null)

    is.close();

    if(bos!=null)

    bos.close();

    } catch (Exception e2) {

    // TODO: handle exception

    }

    }

    return b;

    }

    }

    输出结果:

    249983f59d2345293f867d2fb8b7b4dc.png

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

    展开全文
  • java自定义classLoader

    2020-07-21 20:52:21
    一般这种课题,首先以就要阅读一下官方提供的帮忙文档 实在是太多了,这里就不...java.lang.ClassLoader A class loader is an object that is responsible for loading classes.TheclassClassLoaderis an abstr...

    一般这种课题,首先以就要阅读一下官方提供的帮忙文档

    实在是太多了,这里就不全部列出来了。主要罗列了几个概念,以及一些比较重要的语句。

    抽象类,双亲委托,亲ClassLoader等。

    通过官方提供的样例,我们基本就可以写一个简单的ClassLoader。

    java.lang.ClassLoader

    A class loader is an object that is responsible for loading classes.The class ClassLoader is an abstract class.

    A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.

    The ClassLoader class uses a delegation model to search for classes and resources.

    Each instance of ClassLoader has an associated parent class loader.  When requested to find a class or  resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.

    A sample implementation is:

     * <blockquote><pre>
     *     class NetworkClassLoader extends ClassLoader {
     *         String host;
     *         int port;
     *
     *         public Class findClass(String name) {
     *             byte[] b = loadClassData(name);
     *             return defineClass(name, b, 0, b.length);
     *         }
     *
     *         private byte[] loadClassData(String name) {
     *             // load the class data from the connection
     *             &nbsp;.&nbsp;.&nbsp;.
     *         }
     *     }
     * </pre></blockquote>

    package com.dangxk.tools.test;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     *
     * @author dangxk
     */
    public class MyClassloader extends ClassLoader {
    
        private final String fileSuffix = ".class";
        private String classLocation;
    
        public MyClassloader(String classLocation) {
            super();
            this.classLocation = classLocation;
        }
    
        public MyClassloader(ClassLoader parentClassLoader, String classLocation) {
            super(parentClassLoader);
            this.classLocation = classLocation;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            byte[] classData = loadClassData(name);
            return defineClass(name, classData, 0, classData.length);
        }
    
        private byte[] loadClassData(String name) {
            InputStream is = null;
            ByteArrayOutputStream baos = null;
            byte[] data = null;
            try {
                is = new FileInputStream(new File(classLocation + name.replace(".", "\\") + fileSuffix));
                baos = new ByteArrayOutputStream();
                int r = 0;
                while (-1 != (r = is.read())) {
                    baos.write(r);
                }
                is.close();
                baos.close();
                data = baos.toByteArray();
            } catch (Exception ex) {
                Logger.getLogger(MyClassloader.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    is.close();
                    baos.close();
                } catch (IOException exx) {
                    Logger.getLogger(MyClassloader.class.getName()).log(Level.SEVERE, null, exx);
                }
            }
            return data;
        }
    
        @Override
        public String toString() {
            return "This is MyClassLoader:" + this.getClass().getSimpleName();
        }
    
        public static void main(String[] args) throws Exception {
            MyClassloader myCl = new MyClassloader(ClassLoader.getSystemClassLoader(), "D:\\NetBeansProjects\\tools\\target\\classes\\");
            testClassLoader(myCl);
        }
    
        private static void testClassLoader(MyClassloader cl) throws Exception {
            Class<?> clazz = cl.findClass("com.dangxk.tools.test.EditDistance");
            System.out.println(clazz.getClassLoader().toString());
    
            Object newObj = clazz.newInstance();
            System.out.println(newObj.toString());
        }
    }
    

    输出:

    This is MyClassLoader:MyClassloader
    com.dangxk.tools.test.EditDistance@7852e922

    实现基类(ClassLoader)的 findClass,通过文件系统读入外部的Class文件,转换成byteArray,生成对应的类。

    流程就是这样。

    接下来我们简单看一下在实现代码过程中主要用到的几个方法的官方定义。 

        /**
         * Finds the class with the specified <a href="#name">binary name</a>.
         * This method should be overridden by class loader implementations that
         * follow the delegation model for loading classes, and will be invoked by
         * the {@link #loadClass <tt>loadClass</tt>} method after checking the
         * parent class loader for the requested class.  The default implementation
         * throws a <tt>ClassNotFoundException</tt>.
         *
         * @param  name
         *         The <a href="#name">binary name</a> of the class
         *
         * @return  The resulting <tt>Class</tt> object
         *
         * @throws  ClassNotFoundException
         *          If the class could not be found
         *
         * @since  1.2
         */
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            throw new ClassNotFoundException(name);
        }

    这里的 binary name就是上面例子中的,com.dangxk.tools.test.EditDistance

    binary name官方详解

    后面调用 return defineClass(name, classData, 0, classData.length);

    就可以把从class文件读入的byteArray转化成对应的Class了。

    ※ 通过上面这些步骤我们就完成了用 java.lang.ClassLoader 帮助我们实现自定义类加载器的功能。

     

    接下来是一些方便自己理解的东西,大家如果没有兴趣可以无视,哈哈。

    注意此时我们只是创建了类,并没有加载这个类。

    可以通过给 com.dangxk.tools.test.EditDistance 追加静态代码块儿去确认这个观点。

        /**
         * Converts an array of bytes into an instance of class <tt>Class</tt>.
         * Before the <tt>Class</tt> can be used it must be resolved.
         *
         * <p> This method assigns a default {@link java.security.ProtectionDomain
         * <tt>ProtectionDomain</tt>} to the newly defined class.  The
         * <tt>ProtectionDomain</tt> is effectively granted the same set of
         * permissions returned when {@link
         * java.security.Policy#getPermissions(java.security.CodeSource)
         * <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>}
         * is invoked.  The default domain is created on the first invocation of
         * {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>},
         * and re-used on subsequent invocations.
         *
         * <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use
         * the {@link #defineClass(String, byte[], int, int,
         * java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a
         * <tt>ProtectionDomain</tt> as one of its arguments.  </p>
         *
         * @param  name
         *         The expected <a href="#name">binary name</a> of the class, or
         *         <tt>null</tt> if not known
         *
         * @param  b
         *         The bytes that make up the class data.  The bytes in positions
         *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
         *         of a valid class file as defined by
         *         <cite>The Java&trade; Virtual Machine Specification</cite>.
         *
         * @param  off
         *         The start offset in <tt>b</tt> of the class data
         *
         * @param  len
         *         The length of the class data
         *
         * @return  The <tt>Class</tt> object that was created from the specified
         *          class data.
         *
         * @throws  ClassFormatError
         *          If the data did not contain a valid class
         *
         * @throws  IndexOutOfBoundsException
         *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
         *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
         *
         * @throws  SecurityException
         *          If an attempt is made to add this class to a package that
         *          contains classes that were signed by a different set of
         *          certificates than this class (which is unsigned), or if
         *          <tt>name</tt> begins with "<tt>java.</tt>".
         *
         * @see  #loadClass(String, boolean)
         * @see  #resolveClass(Class)
         * @see  java.security.CodeSource
         * @see  java.security.SecureClassLoader
         *
         * @since  1.1
         */
        protected final Class<?> defineClass(String name, byte[] b, int off, int len)
            throws ClassFormatError
        {
            return defineClass(name, b, off, len, null);
        }
     

    哈哈,又是一大堆,defineClass继续王后追的话,最终调用的就是native方法。就接触到了C++的东西了。

        private native Class<?> defineClass0(String name, byte[] b, int off, int len, ProtectionDomain pd);

        private native Class<?> defineClass1(String name, byte[] b, int off, int len, ProtectionDomain pd, String source);

        private native Class<?> defineClass2(String name, java.nio.ByteBuffer b, int off, int len, ProtectionDomain pd, String source);

    追到这儿,大家应该就明白了。我们差不多到头了。剩下的就只能参考各种文档,加深一下理解。追代码的方式已经不能继续进行了。

    结语:

    总之,从自定义类加载器入手,进一步理解java类加载相关的周边知识。其实这些东西可能在我们平时开发的时候基本上不会用到,但是理解了这些东西就能更好的接近基地实现。挖深一步,就更自信一点儿。

    展开全文
  • java自定义classloader

    2020-06-02 17:15:15
    首先继承ClassLoader类,如果不希望双亲委派,重写loadClass方法,否则重写findClass方法,以下是一次业务中的使用 import org.springframework.util.Base64Utils; import io.renren.common.utils.EncrypAES; ...
  • Java 自定义ClassLoader

    2017-11-17 14:43:42
    废话不多说,按步骤来,直接代码 1.建一个接口文件,代码如下: package Test;...2.自定义一个ClassLoader,代码如下: package Test; import java.io.ByteArrayOutputStream; import java.io.InputStream
  • 由于ClassLoader的单亲委托结构,保证了JVM中加载的类的安全性。BootstrapClassloader会加载java核心库(例如:java.lang.*等);ExtClassloader会加载jdk安装目录下的ext目录下的jar包(即jdk1.6.0_18\jre\lib\ext),...
  • Java自定义ClassLoader实现上文说Java中的ClassLoader机制,在文章末尾说要自定义一个类加载器,现在就来实现下。实现自定义ClassLoader前文说过如果通过classLoader的loadClass方法来加载类,需要实现findClass方法...
  • 目标:实现类的动态加载原理:使用java自定义classloader机制实现类的动态加载。代码实现://自定义classloaderpublicclassStrategyClassLoaderextendsClassLoader{//通过该方法实现类的加载...
  • java 自定义ClassLoader

    2014-07-29 19:38:52
    编写自定义ClassLoader注意2点即可: 1. 想遵循委托模型的话重写findClass方法即可。 2. 不遵循委托模型的话重写loadClass。   其他:defineClass方法把字节数组b中的内容转换成Java 类,返回的结果是 java....
  • java自定义ClassLoader加载指定的class文件实现例子SyncExternalClassLoader loader = new SyncExternalClassLoader();Class> aClass = loader.findClass("bug");object = aClass.newInstance();public class ...
  • Java自定义ClassLoader实现上文说Java中的ClassLoader机制,在文章末尾说要自定义一个类加载器,现在就来实现下。实现自定义ClassLoader前文说过如果通过classLoader的loadClass方法来加载类,需要实现findClass方法...
  • Java自定义ClassLoader加载Class的问题前面两篇介绍了Java中的ClassLoader,如果对ClassLoader不熟悉的朋友可以参考以下文章。Java中的ClassLoader机制Java自定义ClassLoader实现在自定义ClassLoader的时候,我们不...
  • 可是一圈下来,新手们依然不知道如何自定义一个类加载器,来生动的展现什么是类加载器。首先我们在E:upload下新建一个a/BB.java文件。代码如下:packagea;public classBB {privateString a;publicBB(){}publicBB...
  • 继承ClassLoader并且重写findClass方法就可以自定义一个类加载器,具体什么是类加载器以及类加载器的加载过程与顺序下次再说,下面给出一个小demo首先定义一个类,比如MyTest,并且将其编译成class文件,然后放到一...
  • 继承ClassLoader并且重写findClass方法就可以自定义一个类加载器,具体什么是类加载器以及类加载器的加载过程与顺序下次再说,下面给出一个小demo首先定义一个类,比如MyTest,并且将其编译成class文件,然后放到一...
  • [url=https://blog.csdn.net/t894690230/article/details/73252331]Java 自定义 ClassLoader 实现隔离运行不同版本jar包的方式[/url] 1. 应用场景 有时候我们需要在一个 Project 中运行多个不同版本的 jar 包,...
  • 如下图所示,javaclassloader是双亲委派机制。会首先从父classloader加载指定的class,如果加载不到才会从子classloader中加载。 主要这里的图片主要用于体现classloader的父子关系,实际上实现时并不一定存在...
  • 开发环境:JDK1.5 + Eclipse4.X发布类型:zip启动工程源码类型:启动jar包中含有源码运行环境:支持windows、Liunx等平台(其他平台未测试)开发功能说明:1、操作系统通过Java命令启动java虚拟机。2、java虚拟...
  • 疑问:如果要重新加载,则需要用新的classloader,不然会报类重复加载,貌似classloader没有暴露出主动卸载类的接口 package server; import java.io.*; import java.lang.reflect....// 自定义classloader publ...
  • 定义需要加载的类为了能够实现类加载,并展示效果,定义一个Hello类,再为其定义一个sayHello()方法,加载Hello类之后,调用它的sayHello()方法。...}}定义类加载器自定义加载器,需要继承ClassLoade...
  • package ...import java.io.File;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import java.util.ArrayList;import java.util.List;public class ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,530
精华内容 612
关键字:

java自定义classloader

java 订阅