ClassLoader问题剖析

Java ClassLoader深度解析:委派机制、类隔离与实战排错 ClassLoader是Java运行时实现动态加载、类隔离与安全沙箱的核心机制。其本质并非简单工具,而是基于双亲委派模型构建的信任链与隔离边界——通过Bootstrap、Extension、Application三级加载器分工,保障核心类不可篡改、应用类版本可独立。技术价值在于支撑模块化、热部署、SPI服务发现及微服务多租户等关键能力。典型应用场景包括Tomcat WebApp隔离、JDBC驱动加载、Log4j2升级冲突排查及Metaspace内存泄漏治理。本文聚焦ClassLoader的委派原理、自定义陷 阅读详情

一个自定义ClassLoader的例子:

package classloader.test;

import test.loader.MyInterface;

import java.io.*;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;

public class MyClassLoader extends URLClassLoader {
    public MyClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public MyClassLoader(URL[] urls) {
        super(urls);
    }

    public MyClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }

    @Override
    public void addURL(URL url) {//可以添加要资源jar,添加后的jar里的class不会立即被加载,还需要调用loadClass
        super.addURL(url);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            //如果super加载不到就会抛出异常,异常被捕捉,不会返回,super能否加载到取决于是否将对应的jar通过addURL加入进来
            return super.findClass(name);
        } catch (Exception e) {
        }
        //如果super没有加载到,则自定义加载
        byte[] classData = getClassData(name);
        if (classData == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name, classData, 0, classData.length);
        }
    }

    //这里是从文件中获取class的字节数组,也可以从网络获取等。
    private byte[] getClassData(String className) {
        String path = "/home/wangpl/Desktop" + File.separatorChar
                + className.replace('.', File.separatorChar) + ".class";
        try {
            InputStream ins = new FileInputStream(path);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[4096];
            int bytesNumRead = 0;
            while ((bytesNumRead = ins.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesNumRead);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            System.err.println("Log: " + e.getMessage());
        }
        return null;
    }


    public static void main(String[] args) throws Exception {
        String jarFile = "/home/wangpl/Desktop/loader.jar";
//        URL url = new URL("file:" + jarFile);
        URL url = new File(jarFile).toURI().toURL();

//        MyClassLoader loader = new MyClassLoader(new URL[]{url}, null);

        MyClassLoader loader = new MyClassLoader(new URL[0]);
        //loader.addURL(url);

        Class clazz = loader.loadClass("test.loader.MyImpl");

        //call by reflect
        Object obj = clazz.newInstance();
        Method method = clazz.getDeclaredMethod("name", null);
        method.invoke(obj, null);

        //call by interface
        MyInterface myInterface = (MyInterface) obj;
        myInterface.name();
        //看上去很自然,但一定要保证MyInterface和obj被同一个类加载器加载到(含父能加载到)
        //如果MyClassLoader设置父加载器为null,并且可以加载到外部一个MyInterface,那么上面的强转就会出现无法转换异常!
        //举例:我们在上面使用 new MyClassLoader(new URL[]{url}, null);的时候就会看到这个异常
        //原因是:MyClassLoader父加载器设置为了null,那么就会自己去加载loader.jar里面的MyInterface,这样MyImpl实现的接口来自
        //MyClassLoader加载,而在线程中强转时使用MyInterface是被sun.misc.Launcher$AppClassLoader@18d107f加载(查看方式:MyInterface.class.getClassLoader())
        //被不同加载器加载的MyInterface,jvm会认为不是同一个接口也就不能转换。
        //如果不将MyClassLoader的父加载器设null,这样在加载MyInterface时就会优先使用父的,如此,MyImpl才可以和MyInterface对接成功
    }
}
===================================================================================================================

#ClassLoader问题剖析
    做为一个java开发人员,我们都曾经受这些异常的折磨:ClassNotFoundException、NoClassDefFoundError、ClassCastException、ClassCircularityError,究其根源,我们不可避免地要面对java的大人物: ClassLoader !

##ClassLoader基础
java程序不是本地的可执行程序,它的执行依赖jvm,jvm运行后将 class 文件加载到jvm,然后才能在jvm内部运行。负责加载这些class的组件就是ClassLoader。

JVM本身包含了一个ClassLoader称为**BootstrapClassLoader**,和JVM自身一样,**BootstrapClassLoader**是用本地代码(c/c++等)实现的,它负责加载核心Java  class(如rt.jar里的class)。另外JVM还提供了两个ClassLoader,它们都是用Java语言编写的,由BootstrapClassLoader加载到jvm,它们是**ExtClassLoader**和**AppClassLoader**,其中**ExtClassLoader**负责加载Java扩展 class(如jre/lib/ext下的类),**AppClassLoader**负责加载应用程序自身的类(如-classpath下的class)。

当运行一个程序的时候,JVM启动,运行Bootstrap ClassLoader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后调用AppClassLoader加载应用CLASSPATH下定义的Class,这就是一个程序最基本的加载流程。

JVM自带的ClassLoader只是懂得从本地文件系统加载标准的java class文件,但是我们可能会有下面的应用场景:
1)在执行类加载之前,自动验证数字签名
2)动态地创建符合用户特定需要的定制化构建类
3)从特定的场所取得 class,例如数据库、网络等
4) 自定义加解密Class 等等
这时候我们就需要定制自己的ClassLoader,java提供了很方便的api供我们定制自己的ClassLoader。

    事实上当使用Applet的时候,就用到了特定的ClassLoader,因为需要从网络上加载java class,并且要检查相关的安全信息。另外,应用服务器大都使用了自定义ClassLoader技术,了解类加载原理也有助于我们更好地开发自己的应用。

##ClassLoader结构
java中内置了很多类加载器,本文只讨论几个核心类加载器:
**ClassLoader**:所有类加载器的基类,它是抽象的,定义了类加载最核心的操作。
**SecureClassLoader**:继承自ClassLoader,添加了关联类源码、关联系统policy权限等支持。
**URLClassLoader**:继承自SecureClassLoader,支持从jar文件和文件夹中获取class
**ExtClassLoader**:扩展类加载器,继承自URLClassLoader,负责加载java的扩展类(javax.*等),查看源码可知其查找范围为System.getProperty("java.ext.dirs"),通常是jre/lib/ext
**AppClassLoader**:应用类加载器,继承自URLClassLoader,也叫系统类加载器(ClassLoader.getSystemClassLoader()可得到它),它负载加载应用的classpath下的类,查找范围System.getProperty("java.class.path"),通过-cp或-classpath指定的类都会被其加载

    java没有提供Launcher的源码,可参考openjdk的Launcher类源码。

上面介绍的是ClassLoader的静态类结构,在概念上,它们还有树形结构,java中的每个ClassLoader都有自己的父加载器(**注意区分,不是类关系上的 super**),可以通过ClassLoader.getParent() 获取到,当jvm启动完成后,默认情况下,他们的树形结构是这样的:
自定义的ClassLoader其父加载器为AppClassLoader,
AppClassLoader的父加载器为ExtClassLoader,
ExtClassLoader的父加载器为null,
null表示其父加载器为 BootstrapClassLoader(非java实现故显示为null)。

##ClassLoader类加载模型
ClassLoader加载类用的是委托模型(也叫双亲委派模型)。即先让父加载器(注意不是super,不是继承关系的父,而是通过一个属性保存了一个父的引用)加载,父加载器加载不到才能轮到自己加载。

需要注意:**父加载器加载到的类对子加载器可见,但子加载器加载到的类对父加载器是不可见的**,这句话很好理解,但往往因为它产生的问题都不好分析。

需要注意:在jvm中,一个class实例的唯一标识是:**类全名+ClassLoader**,所以,**经由不同ClassLoader加载到的相同类全名的class也是不相同的**,它们的类型也是不兼容的,这也是某些类型转换异常的原因,这种异常通常也不好分析。

    要想看到类装入详细信息,可以用 -verbose:class 选项启动。详细输出有助于解决类路径问题,例如没有打开 JAR 文件(因此不在类路径中)或从错误的位置装入了类等。

查看Launcher的构造函数,有如下:

        // Create the extension class loader
        ClassLoader extcl;
        try {
            extcl = ExtClassLoader.getExtClassLoader();
        } catch (IOException e) {
            throw new InternalError(
                "Could not create extension class loader");
        }

        // Now create the class loader to use to launch the application
        try {
            loader = AppClassLoader.getAppClassLoader(extcl);
        } catch (IOException e) {
            throw new InternalError(
                "Could not create application class loader");
        }

        // Also set the context class loader for the primordial thread.
        Thread.currentThread().setContextClassLoader(loader);
    ....
从Launcher的构造方法中,可以看出Launcher的构造先创建了ExtClassLoader,后又创建了AppClassLoader,并将AppClassLoader的父ClassLoader设为ExtClassLoader,最后,取得当前线程,**并将当前线程的ContextClassLoader设为AppClassLoader**。

再查看Thread的构造函数,会得知,Thread在构造时候会**取得当前线程,并将当前线程的contextClassLoader赋给新创建的线程**。
    我们在建立一个线程Thread的时候,可以为这个线程通过setContextClassLoader方法来指定一个**合适的classloader**作为这个线程的context classloader,当此线程运行的时候,我们可以通过getContextClassLoader方法来获得此context classloader,就可以用它来**载入我们所需要的Class**。**默认的就是system classloader**(从上面源码中可得知)。利用这个特性,我们可以**“打破”classloader委托机制**了,父classloader可以获得当前线程的context classloader,**而这个context classloader可以是它的子classloader或者其他的 classloader**,那么父classloader就可以从其获得所需的 Class,这就**打破了只能向父classloader请求的限制**了。这个机制可以满足我们的**classpath是在运行时才能确定**的需求,可以通过context classloader获得定制的classloader并加载入特定的class,例如web应用中的servlet等技术就是用这种机制加载的。

    Classloader虽然称为类加载器,但并不意味着只能用来加载Class,我们还可以利用它也获得图片,音频文件等资源的URL,当然,这些资源必须在CLASSPATH中的jar类库中或目录下。因此我们可以将图片等资源随同Class一同打包到jar类库中(当然,也可单独打包这些资源)并添加它们到class loader的搜索路径中,我们就无需关心这些资源的具体位置了,让class loader来帮我们寻找吧!

##一些类加载问题示例
###示例1
两个类,A、B, A依赖B,B不依赖A,将两者分别放于不同的目录加载,有以下现象:
1)B放于jre/lib/ext下,A放于classpath下,正常。
2)A放于jre/lib/ext下,B放于classpath下,报错:java.lang.NoClassDefFoundError:B
出错原因:A放于jre/lib/ext下,其ClassLoader为ExtClassLoader(可通过Class.getClassLoader()查看),B放于classpath下,其ClassLoader为AppClassLoader,ExtClassLoader是AppClassLoader的父加载器,故ExtClassLoader无法加载到B就会报错。这是个很基础的示例,同时也是很多类加载不到案例的问题模型。

    有人会想,将两个类放一起就没有这个顾虑了,的确是,但事实上有时候它们无法放到一起,比如web开发中,javax中定义了很多接口(如jdbc规范)默认都被放在系统类路径下,而它们的实现(如mysql驱动)往往被放在web应用自定义的类路径下,他们的开发和部署都是分开的,一般不会放到一起,继续看下面的案例会更有体会。

###案例2
在JAXP(XML处理相关) 中的, javax.xml.parsers.DocumentBuilderFactory类(位于rt.jar)的 newInstance()方法用来生成一个新的 DocumentBuilderFactory的实例,此实例必需是javax.xml.parsers.DocumentBuilderFactory的实现类,它是由JAXP的SPI具体实现所提供的,如 Apache Xerces 中的 org.apache.xerces.jaxp.DocumentBuilderFactoryImpl,
问题出现了,SPI 的接口是 Java 核心库的一部分,是由引导类加载器来加载的,SPI 的实现一般都是由系统类加载器来加载的,引导类加载器无法加载到SPI的实现类,那么SPI的接口如何使用SPI的实现呢?
答案就是:**线程上下文类加载器**。
如果不做任何的设置,线程的上下文类加载器默认就是系统上下文类加载器(AppClassLoader)。在 SPI 接口的代码中使用线程上下文类加载器,就可以成功的加载到 SPI 实现的类。
    
    线程上下文类加载器在很多 SPI 的实现机制中都会用到。
##ClassLoader异常
###ClassNotFoundException
ClassNotFoundException 是最常见的类装入异常。它发生在装入阶段。Java 规范对它的描述是这样的:
当应用程序试图**通过类的字符串名称**以下面三种方法装入类但却找不到指定名称时就会抛出该异常。
1)类 Class 中的 forName() 方法。
2)类 ClassLoader 中的 findSystemClass() 方法。
3)类 ClassLoader 中的 loadClass() 方法。

所以,**显式装入类失败,就会抛出 ClassNotFoundException**, -verbose 启动参数可打印出详细的类装入信息,
要修复这个问题,可以把类移动到类路径中指定的目录或JAR文件中,或者把类所在的位置添加到类路径中。
###NoClassDefFoundError
JVM 规范对 NoClassDefFoundError 的定义如下:
ClassLoader试图装入**类定义**(类结构或方法等的一部分,可理解为类的依赖),但却没有找到类定义时抛出该异常。

通常此异常抛出在在这样的场景,我们试图装入一个类(显示装入),该类可以找到,然而装入过程中发现此类有依赖其它类,此时就去**隐式转入其依赖类**,如果没有找到其依赖类,则认为其依赖类没有定义,就会抛出此异常。

**NoClassDefFoundError 的抛出,是不成功的隐式类装入的结果**。
示例代码:
public class NoClassDefFoundErrorTest {
    public static void main(String[] args) {
        A a = new A();
    }
}
public class A extends B {
}
public class B {
}
这几个清单中的代码编译好之后,删除B的类文件。当代码执行时,就会出现以下错误:Exception in thread "main" java.lang.NoClassDefFoundError: B
如果显式地告诉类装入器装入类 B(例如通过 loadClass("B") 调用),那么就会抛出 ClassNotFoundException,注意这两个异常的区别。

在这个例子中,A 继承了 B,即使 A 用其他方式引用 B,也会出现同样的问题,例如,以方法参数引用或作为实例字段。如果两个类之间的关系是引用关系而不是继承关系,那么会在**第一次使用**到时抛出异常,而**不是在装入** A 时抛出。

###ClassCastException
JVM 规范定义:
    当代码企图把对象的类型转换成一个子类,而该对象并不是这个子类的实例时就会抛出该异常。
    一般来说,父类转换到子类出现不兼容的场景是很容易发现并修订的,如String可以转换为Object,而Object不能转换到String,但是有一类问题却不容易解决,比如我们定义一个接口MyInterface,和其实现类MyImpl,并一起打包进loader.jar,我们会有类似如下的代码:
    URL url = new URL("file:/home/wangpl/Desktop/loader.jar");
    URLClassLoader loader = new URLClassLoader(new URL[]{url}, **null**);//设置父加载器为null
    Class clazz = loader.loadClass("test.loader.MyImpl");
    Object obj = clazz.newInstance();
    **MyInterface myInterface = (MyInterface) obj;**
    这个看似很正常的代码却会出现 转换异常,原因在于我们使用了自己的URLClassLoader,并且其父加载器为null,它在加载MyImpl时,发现它实现了MyInterface接口,于是就去找MyInterface的定义,因为父为null,只能自己从loader.jar中加载,此时,MyImpl实现的接口就是URLClassLoader加载的MyInterface,然而在代码中,我们使用的MyInterface是由系统类加载器(AppClassLoader)加载的,所以会发生类型不兼容的现象,这也再次印证了:jvm里Class实例的唯一标识是类 全名+ClassLoader。
    上述问题的解决方案:去掉父加载器为null的代码,这样我们URLClassLoader在寻找MyInterface定义的时候就会优先从父加载器中寻找,这样就会忽略掉自己的MyInterface,如此,MyImpl实现的是系统加载器的MyInterface,转换便没有异常。
###UnsatisfiedLinkError
在JNI开发中,如果程序试图装入一个不存在或者位置放错的本机库时,在链接阶段的解析过程会发生 UnsatisfiedLinkError。
JVM 规范指定 UnsatisfiedLinkError 是:
    对于声明为 native 的方法,如果jvm找不到和它对应的本机语言定义,就会抛出该异常。
示例代码:
public class UnsatisfiedLinkErrorTest {
    public native void call_A_Native_Method();
    static {
        System.loadLibrary("myNativeLibrary");
    }
    public static void main(String[] args) {
        new UnsatisfiedLinkErrorTest().call_A_Native_Method();
    }
}
error:The java class could not be loaded. java.lang.UnsatisfiedLinkError...

要装入所引用的本机库,这个类装入器先查找 sun.boot.library.path,然后查找 java.library.path。因为在两个位置中都没有需要的库,所以类装入器抛出 UnsatisfiedLinkageError。
一旦理解了库装入过程所涉及的类装入器,就可以通过把库放在合适位置来解决这类问题。

###ClassCircularityError
下面的代码展示了类或接口由于是自己的超类或超接口而不能被装入。
public class A extends B {
}
public class B {
}
public class A {
}
public class B extends A {
}
这个错误是在链接阶段的解析过程中抛出的。这个错误有点奇怪,因为 Java 编译器不允许发生这种循环情况。但是,如果独立地编译类,然后再把它们放在一起,就可能发生这个错误,比如单独编译上面两个或下面两个都不会出错,这样就可以形成了循环依赖的情景,这种类结构在resolve过程中就会抛出异常。

###ClassFormatError
这个异常是在类装入的链接阶段的校验过程中抛出。如果字节码发生了更改,例如主版本号或次版本号发生了更改,那么二进制数据的形式就会有误。例如,如果对字节码故意做了更改,或者在通过网络传送类文件时现出了错误,那么就可能发生这个异常。
修复这个问题的惟一方法就是获得字节码的正确副本,可能需要重新进行编译。
    
    tongweb遇到的一个jdk1.8不兼容的问题就报出了这个异常,原因是因为jdk1.8中的HashMap中的内部类Entry去掉了,即class版本改变。

###ExceptionInInitializerError
如果在初始化过程中突然结束,抛出一些异常 E,而且 E 的类不是 Error 或者它的某个子类,那么就会创建 ExceptionInInitializerError 类的一个新实例(Error和Exception平级,无继承关系,它们都直接继承自Throwable),并用 E 作为参数,用这个实例代替 E。
如果jvm在试图创建类 ExceptionInInitializerError 的实例时,因为出现 Out-Of-Memory-Error 而无法创建新实例,那么就抛出 OutOfMemoryError 对象作为代替。
下面代码会出现这种异常:
public class ExceptionInInitializerErrorTest {
    public static void main(String[] args) {
        A a = new A();
    }
}
class A {
    static {
            throw new SecurityException();//Exception的子类,不是Error的子类
    }
}
示例中的静态代码块中发生异常时,会被自动捕捉并用 ExceptionInInitializerError 包装该异常。在输出中可以看到:
Exception in thread "main" java.lang.ExceptionInInitializerError
   at ExceptionInInitializerErrorTest.main(ExceptionInInitializerErrorTest.java:3)
**Caused by: java.lang.SecurityException**
   **at A.&lt;clinit&gt;**(ExceptionInInitializerErrorTest.java:12)
   ... 1 more
   修复这个错误的方法是检查造成 ExceptionInInitializerError 的异常(**在堆栈跟踪的 Caused by ... 下显示**)并寻找阻止抛出这个异常的方式。

###简谈Class热替换
java本身不支持热替换,即当class文件已经被加载到内存,这时再使用新编译的class文件替换不会有任何变化,这很好理解,因为java本身不会检测class文件的变动,但是,即便是我们手动调用ClassLoader再次加载此类,依旧不会有任何变化,原因是,在同一个ClassLoader内是以包名+类名做唯一标识,如果新编译的class文件包名+类名没有变化(热替换肯定不会变化),就不会再次解析该class文件而是直接返回之前解析到的Class(每个被加载的Class都会在ClassLoader内部缓存)。
**如何热替换?**
既然在同一个ClassLoader内部无法进行二次加载同一个类,那么要想加载并解析到新的类文件就必需使用一个未曾加载过此类的ClassLoader,即**使用一个新的ClassLoader加载新的类文件**,这也是热替换方案的必经之路。
一般做法:
1.为需要热替换的Class创建一个接口,目的是引用Class的实例并在其更新后转而引用其新的实例。
2.开一个定时线程,周期性检测Class文件是否有改动(可检测文件的最后修改时间是有变化),如果有改动则创建一个新的ClassLoader加载此Class文件,得到一个新的Class,新的Class通过使用反射技术得到一个实例,再将此实例强转为之前定义的接口,之后再对此接口引用,就可看到更新后的变化。

    这种替换方案也只能对后来引用的上下文产生影响,更新前的实例依旧不会也不可能被替换掉,所以如果要制定热替换方案,则需要多加考虑接口的使用方式与实例的生命周期等因素,以确保不要总是守着旧的实例不放而使用不到新的实例,可以考虑使用统一的实例接口引用方法来进行控制。另外也要记得及时切断对旧实例的引用并通知GC进行回收。

##结束   
要更深入地了解ClassLoader,搜索:**OSGI**
Java中Groovy脚本执行引发的MetaSpace内存泄露分析与解决方案 在Java应用开发中,动态脚本执行是扩展系统灵活性的常见需求,Groovy作为JVM上的动态语言,因其与Java的无缝集成和强大的动态能力被广泛应用于规则引擎、工作流和插件系统等场景。其核心原理是通过GroovyClassLoader动态编译脚本为Java类并加载到JVM的MetaSpace(元空间)中。然而,若ClassLoader生命周期管理不当,动态生成的类及其元数据将无法被垃圾回收,导致MetaSpace内存持续增长直至OOM,这就是典型的内存泄露问题。该问题的技术价值在于揭示了JVM类加载与卸载机 阅读详情

相关推荐

一看你就懂,超详细java中的ClassLoader详解

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见。理解ClassLoader的加载机制,也有利于我们编写出更高效的代码。ClassLoader的具体作用就是将class文件加载到jvm虚拟机中去,程序就可以正确运行了。但是,jvm启动的时候,并不会一次性加载所有的...

frank 的专栏 34万+

java安全——类加载和Unsafe类(ClassLoader,URLClassLoader)

当要执行某一个类时,java程序在运行前会将java文件编译成class字节码文件,然后调用ClassLoader类加载器加载类字节码,通过JVM的native方法来创建类的class对象。 使用javap命令反编译HelloTest.class文件查看其内容 用工具以十六进制打开.class文件的二进制内容,jvm执行HelloTest类会解析class文件中的字节码内容(ByteCode) ClassLoader类加载器 ClassLoader类加载器主要是用于加载jav..

网络安全 2322

Akamai移动端Sensor数据采集与BMP风控机制深度解析

本文深度解析了Akamai在移动端风控中的核心机制,重点阐述了Sensor数据如何通过采集陀螺仪、加速度计等硬件信息,结合设备指纹生成连续且符合物理规律的行为轨迹。详细剖析了数据从采集、加密校验到通过BMP风控三重验证(校验位、时间差、数据逻辑)的完整流程,并提供了从模拟优化到自建风控模型的实用应对思路。

quiet的专栏 285

JVM系列之ClassLoader

类加载器介绍 类加载器负责加载JAVA类的字节码到JAVA虚拟机中,可理解成JVM和字节码代码的桥梁,可以根据指定的类名(如java.lang.Object)来装载class文件的内容到Runtime data area 中的 method area( 方法区域)。 从JVM的角度讲,主要有两种类型加载器:启动类加载器和所有其它的类加载器。启动类加载器是JVM实现的一部分,使用C++语言实现,其它类加载器都由java语言实现,独立于虚拟机外部,并且全部继承抽象类java.lang.ClassLoader。

zhao6406879的博客 548

R以及Rstudio超详细安装教程(包括安装过程中出现的问题)

R安装及Rstudio安装,以及安装中出现的问题

2301_76908257的博客 1万+

抖音a_bogus参数逆向避坑指南:从环境检测到XHR请求的全流程解析

本文详细解析了抖音a_bogus参数在v1.0.1.19版本下的逆向工程全流程,重点介绍了如何通过PyV8Env框架进行有效的补环境操作,以绕过严格的环境检测。内容涵盖从环境初始化、关键事件触发到模拟XHR请求获取签名的完整步骤,并提供了可运行的Python代码示例和常见检测点的避坑指南,帮助开发者稳定生成有效的a_bogus参数。

tech5的博客 600

深度分析Java的ClassLoader机制(源码级别)

深度分析Java的ClassLoader机制(源码级别) 写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass使用双亲委派模式。 为了...

weixin_34138377的博客 341

无限维李代数局部与2-局部1/2-导子:从概念到Witt代数实例解析

在抽象代数与数学物理中,李代数是描述对称性的基本结构,而导子则是刻画其微分性质的核心算子。从经典的导子概念出发,通过引入“局部”与“分数阶”两个关键推广,形成了局部导子、2-局部导子以及1/2-导子等重要研究方向。这些推广不仅深化了对无限维李代数(如Witt代数、Virasoro代数)复杂结构的理解,其研究方法和结论也为共形场论、可积系统等物理理论提供了数学基础。本文聚焦于无限维李代数上局部与2-局部1/2-导子的系统研究,通过拆解核心概念、剖析典型代数结构,并以Witt代数为实例,详细演示了从全局1/2-

weixin_34072296的博客 392

第05讲:深入理解 ClassLoader 的加载机制

深入理解 ClassLoader 的加载机制

ChinaDragon10的博客 3741

如何将TDengine集成到Thingsboard?

1 概述 ThingsBoard是用于数据收集、处理、可视化和设备管理的开源物联网平台。它通过行业标准的物联网协议MQTT、CoAP和HTTP实现设备连接,并支持云和本地部署。 ThingsBoard迄今没有导入专业的时序数据库应用,用户可选择的只有PostgreSQL和Cassandra。虽然针对PostgreSQL引入了TimeScale插件,但由于其不是按照宽表的方式组织数据记录,TimeScale的优势根本发挥不出来。总之,这两种数据库不具备高效的数据吞吐能力。 而且,Thingsboard在

Wearable_device的博客 4767

国家基本比例尺分幅土地利用现状图制作

本次主要解决的问题是如何构建脚本快速生成所涉及区域标准国家基本比例尺分幅,然后制作土地利用现状图模板,套用模板生成标准分幅土地利用现状图。

xyt1172228177的博客 2458

3分钟看懂JVM类加载器Classloader源码深度剖析

在看这篇文章之前,先找到Classloader.class这个类,然后对照下文: ClassLoader与现有类加载器的关系: ClassLoader是一个抽象类。如果我们给定了一个类的二进制名称,类加载器应尝试去定位或生成构成定义类的数据。一种典型的策略是将给定的二进制名称转换为文件名,然后去文件系统中读取这个文件名所对应的class文件。 ClassLoader的主要方法 抽象类ClassLoader的主要方法:(内部没有抽象方法) public fi...

王傲旗的大数据之路 700

手把手教你学Simulink——基于多能互补微电网系统的建模与优化场景实例:风柴储联合供电系统在孤岛模式下的功率分配建模

本文介绍了使用MATLAB/Simulink和Simscape Electrical构建风柴储联合供电系统的建模方法。系统包含风力发电、柴油发电、储能电池等模块,重点研究孤岛模式下功率分配策略。详细说明了从创建项目、添加模块到搭建风力发电系统(含MPPT控制)、柴油发电系统及集成各模块的全过程,并提供了仿真参数设置建议。通过分析频率偏差、电池SOC等关键指标,验证了系统在维持稳定运行的同时能有效利用可再生能源。该模型为研究多能互补微电网提供了实验平台,未来可拓展更高效的能量管理策略和AI技术的应用。

MHD0815的博客 1万+

Java隐式内存泄漏排查与ThreadLocal、ClassLoader问题解决

内存泄漏是Java应用中常见的问题,其中隐式内存泄漏因难以通过常规工具检测而更具挑战性。这类问题通常涉及JVM内存管理机制,特别是ThreadLocal和ClassLoader的使用不当会导致对象无法被GC回收。从技术原理看,ThreadLocal通过线程隔离存储数据,而ClassLoader负责类加载,两者的生命周期管理不当都会引发内存问题。在工程实践中,结合MAT、Arthas等工具进行堆内存分析,并监控ClassLoader数量和ThreadLocal使用情况是关键。典型的应用场景包括长时间运行的微服

weixin_30616969的博客 410

Hermes Agent 对阵 OpenClaw:自我改进的 AI 队友

但在 2026 年 2 月,Nous Research 发布了 Hermes Agent,它带来了不同的愿景:一个不仅能够运行,还能学习的代理。在完成复杂的多步骤任务后,它会分析自己的操作并创建一个可复用的技能。对于已在使用 OpenClaw 的澳大利亚企业而言,这意味着您可以试用 Hermes Agent,而无需丢失数月的配置和自定义成果。最重要的区别在于理念:OpenClaw 是一个需要配置的工具,而 Hermes Agent 则是一个会学习的队友。OpenClaw 的技能是静态的。

xiaoshun007的专栏 1571

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

深入剖析Gradle构建系统核心机制:插件ClassLoader、任务增量快照与守护进程通信

机制源码关键点数据结构/协议典型场景插件ClassLoader多插件隔离加载,避免Class冲突增量快照只重编更改文件相关任务,极大提升构建效率Daemon通信Kryo二进制协议守护进程复用JVM,Socket传递构建请求与响应。

IT技术学习与工作笔记分享 1944

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

android 自定义class,关于Android中自定义ClassLoader耗时问题的追查

前言Android中类加载器有BootClassLoader,URLClassLoader,PathClassLoader,DexClassLoader,BaseDexClassLoader,等都最终继承自java.lang.ClassLoader最近在优化西瓜视频客户端冷启动速度时,发现在关闭插件 ClassLoader 注入的情况下,启动速度提升了300ms左右,但是西瓜在启动阶段并没有使用到...

weixin_39627408的博客 335

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ClassLoader 深入分析

本文章来源于:https://github.com/Zeb-D/my-review ,请star 强力支持,你的支持,就是我的动力。 [TOC] 深入分析 老大难的 Java ClassLoader ClassLoader是 Java 届最为神秘的技术之一,无数人被它伤透了脑筋,摸不清门道究竟在哪里。网上的文章也是一篇又一篇,经过本人的亲自鉴定,绝大部分内容都是在误导别人。【相信】你们彻底吃透 ...

在此立一个IT职业上的flag:https://github.com/Zeb-D/my-review 1万+

Java核心知识点-ClassLoader详解

ClassLoader ClassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回这个类的class对象。 1.1 几个相关概念ClassLoader负责载入系统的所有Resources(Class,文件,来自网络的字节流等),通过ClassLoader从而将资源载入JVM  每个class都有一个ref

一次次成长的过程 7394

Spring Cloud微服务下IDEA热部署失效的终极归因:不是插件问题,而是Bootstrap ClassLoader与AppClassLoader双栈污染(含Arthas实时诊断脚本)

定位Spring Cloud微服务中IDEA热部署插件失效根因,揭示Bootstrap与App ClassLoader双栈污染机制;提供Arthas实时诊断脚本,精准识别类加载冲突。适用于Spring Boot 2.x/3.x微服务开发调试,提升热更新可靠性,值得收藏。

CompiTide的博客 174

27. ClassLoader加载机制 - 插件化基础

/ 1. 分配Class对象// 2. 设置Class基本信息// 3. 加载类成员(字段、方法)// 4. 链接类if (!// 5. 注册类到ClassTablereturn;// 空类// 加载静态字段for (;// 加载实例字段for (;// 加载直接方法(构造函数、静态方法、私有方法)for (;// 加载虚方法for (;ClassLoader体系BootClassLoader加载系统类PathClassLoader加载应用类。

时代我西的博客 823

Java ClassLoader 深入理解

ClassLoader问题剖析做为一个java开发人员,我们都曾经受这些异常的折磨:ClassNotFoundException、NoClassDefFoundError、ClassCastException、ClassCircularityError,究其根源,我们不可避免地要面对java的大人物: ClassLoader ! ClassLoader基础java程序不是本地的可执行程序,它的执行依

王鹏亮 的专栏 1万+

老大难的 Java ClassLoader 再不理解就老了

ClassLoader 做什么的? 顾名思义,它是用来加载 Class 的。它负责将 Class 的字节码形式转换成内存形式的 Class 对象。字节码可以来自于磁盘文件 *.class,也可以是 jar 包里的 *.class,也可以来自远程服务器提供的字节流,字节码的本质就是一个字节数组 []byte,它有特定的复杂的内部格式。 有很多字节码加密技术就是依靠定制 ClassLoader...

weixin_43770982的博客 163

Java低代码组件性能断崖式下跌?深度剖析Classloader隔离失效与热重载内存泄漏(JVM调优实测数据支撑)

解决Java低代码组件性能骤降难题,通过Classloader隔离修复与热重载内存泄漏治理方案。结合真实JVM调优实测数据,适用于Spring Boot低代码平台场景,提供可复用的Java低代码组件示例及监控脚本。稳定性与启动效率双提升,值得收藏。

IterStream的博客 203

揭秘某省政务云Java系统国产化失败真相:中间件适配中被忽视的4个ClassLoader陷阱

揭秘Java国产化中间件适配开发中ClassLoader四大陷阱,提供政务云Java系统迁移落地的避坑指南。聚焦WebLogic→东方通TongWeb、WebSphere→金蝶Apusic等典型场景,详解类加载委托机制、OSGi模块隔离、SPI服务发现及热部署兼容方案。实战性强,值得收藏。

PixelShoal的博客 410

为什么你的Spring Boot在IDEA能编译却无法启动?揭秘IntelliJ IDEA 2023.3+与Spring Boot 3.2.x的ClassLoader隔离机制(附patch级兼容方案)

快速解决IDEA Spring Boot启动报错问题!针对IntelliJ IDEA 2023.3+与Spring Boot 3.2.x因ClassLoader隔离导致的启动失败,提供无需降级的patch级兼容方案,稳定高效。适用于Maven多模块项目及DevTools热部署场景,值得收藏。

FastSolve的博客 192
上一篇: Master worker并行设计模式
下一篇: Apache +Tomcat负载均衡配置
conquer0715
博客等级 码龄18年 73粉丝 147原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值