`
jimode2013
  • 浏览: 39382 次
社区版块
存档分类
最新评论

Java Reflection - Dynamic Class Loading and Reloading

阅读更多

It is possible to load and reload classes at runtime in Java, though it is not as straightforward as one might have hoped. This text will explain when and how you can load and reload classes in Java.

You can argue whether Java's dynamic class loading features are really part of Java Reflection, or a part of the core Java platform. Anyways, the article has been put in the Java Reflection trail in lack of a better place to put it.

Here is a list of the topics covered in this text:

  1. The ClassLoader
  2. The ClassLoader Hierarchy
  3. Class Loading
  4. Dynamic Class Loading
  5. Dynamic Class Reloading
  6. Designing your Code for Class Reloading
  7. ClassLoader Load / Reload Example

The ClassLoader

All classes in a Java application are loaded using some subclass of java.lang.ClassLoader. Loading classes dynamically must therefore also be done using a java.lang.ClassLoader subclass.

When a class is loaded, all classes it references are loaded too. This class loading pattern happens recursively, until all classes needed are loaded. This may not be all classes in the application. Unreferenced classes are not loaded until the time they are referenced.

The ClassLoader Hierarchy

Class loaders in Java are organized into a hierarchy. When you create a new standard Java ClassLoader you must provide it with a parent ClassLoader. If a ClassLoader is asked to load a class, it will ask its parent class loader to load it. If the parent class loader can't find the class, the child class loader then tries to load it itself.

Class Loading

The steps a given class loader uses when loading classes are:

  1. Check if the class was already loaded.
  2. If not loaded, ask parent class loader to load the class.
  3. If parent class loader cannot load class, attempt to load it in this class loader.

When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this sequence. The classes to reload should not be requested loaded by the parent class loader. More on that later.

Dynamic Class Loading

Loading a class dynamically is easy. All you need to do is to obtain a ClassLoader and call its loadClass()method. Here is an example:

public class MainClass {

  public static void main(String[] args){

    ClassLoader classLoader = MainClass.class.getClassLoader();

    try {
        Class aClass = classLoader.loadClass("com.jenkov.MyClass");
        System.out.println("aClass.getName() = " + aClass.getName());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

Dynamic Class Reloading

Dynamic class reloading is a bit more challenging. Java's builtin Class loaders always checks if a class is already loaded before loading it. Reloading the class is therefore not possible using Java's builtin class loaders. To reload a class you will have to implement your own ClassLoader subclass.

Even with a custom subclass of ClassLoader you have a challenge. Every loaded class needs to be linked. This is done using the ClassLoader.resolve() method. This method is final, and thus cannot be overridden in yourClassLoader subclass. The resolve() method will not allow any given ClassLoader instance to link the same class twice. Therefore, everytime you want to reload a class you must use a new instance of your ClassLoadersubclass. This is not impossible, but necessary to know when designing for class reloading.

Designing your Code for Class Reloading

As stated earlier you cannot reload a class using a ClassLoader that has already loaded that class once. Therefore you will have to reload the class using a different ClassLoader instance. But this poses som new challenges.

Every class loaded in a Java application is identified by its fully qualified name (package name + class name), and theClassLoader instance that loaded it. That means, that a class MyObject loaded by class loader A, is not the same class as the MyObject class loaded with class loader B. Look at this code:

MyObject object = (MyObject)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Notice how the MyObject class is referenced in the code, as the type of the object variable. This causes theMyObject class to be loaded by the same class loader that loaded the class this code is residing in.

If the myClassReloadingFactory object factory reloads the MyObject class using a different class loader than the class the above code resides in, you cannot cast the instance of the reloaded MyObject class to the MyObjecttype of the object variable. Since the two MyObject classes were loaded with different class loaders, the are regarded as different classes, even if they have the same fully qualified class name. Trying to cast an object of the one class to a reference of the other will result in a ClassCastException.

It is possible to work around this limitation but you will have to change your code in either of two ways:

  1. Use an interface as the variable type, and just reload the implementing class.
  2. Use a superclass as the variable type, and just reload a subclass.

Here are two coresponding code examples:

MyObjectInterface object = (MyObjectInterface)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");
MyObjectSuperclass object = (MyObjectSuperclass)
    myClassReloadingFactory.newInstance("com.jenkov.MyObject");

Either of these two methods will work if the type of the variable, the interface or superclass, is not reloaded when the implementing class or subclass is reloaded.

To make this work you will of course need to implement your class loader to let the interface or superclass be loaded by its parent. When your class loader is asked to load the MyObject class, it will also be asked to load theMyObjectInterface class, or the MyObjectSuperclass class, since these are referenced from within theMyObject class. Your class loader must delegate the loading of those classes to the same class loader that loaded the class containing the interface or superclass typed variables.

ClassLoader Load / Reload Example

The text above has contained a lot of talk. Let's look at a simple example. Below is an example of a simpleClassLoader subclass. Notice how it delegates class loading to its parent except for the one class it is intended to be able to reload. If the loading of this class is delegated to the parent class loader, it cannot be reloaded later. Remember, a class can only be loaded once by the same ClassLoader instance.

As said earlier, this is just an example that serves to show you the basics of a ClassLoader's behaviour. It is not a production ready template for your own class loaders. Your own class loaders should probably not be limited to a single class, but a collection of classes that you know you will need to reload. In addition, you should probably not hardcode the class paths either.

public class MyClassLoader extends ClassLoader{

    public MyClassLoader(ClassLoader parent) {
        super(parent);
    }

    public Class loadClass(String name) throws ClassNotFoundException {
        if(!"reflection.MyObject".equals(name))
                return super.loadClass(name);

        try {
            String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
                            "classes/reflection/MyObject.class";
            URL myUrl = new URL(url);
            URLConnection connection = myUrl.openConnection();
            InputStream input = connection.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();

            while(data != -1){
                buffer.write(data);
                data = input.read();
            }

            input.close();

            byte[] classData = buffer.toByteArray();

            return defineClass("reflection.MyObject",
                    classData, 0, classData.length);

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace(); 
        }

        return null;
    }

}


Below is an example use of the MyClassLoader.

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

    ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class myObjectClass = classLoader.loadClass("reflection.MyObject");

    AnInterface2       object1 =
            (AnInterface2) myObjectClass.newInstance();

    MyObjectSuperClass object2 =
            (MyObjectSuperClass) myObjectClass.newInstance();

    //create new class loader so classes can be reloaded.
    classLoader = new MyClassLoader(parentClassLoader);
    myObjectClass = classLoader.loadClass("reflection.MyObject");

    object1 = (AnInterface2)       myObjectClass.newInstance();
    object2 = (MyObjectSuperClass) myObjectClass.newInstance();
    
}


Here is the reflection.MyObject class that is loaded using the class loader. Notice how it both extends a superclass and implements an interface. This is just for the sake of the example. In your own code you would only have to one of the two - extend or implement.

public class MyObject extends MyObjectSuperClass implements AnInterface2{
    //... body of class ... override superclass methods
    //    or implement interface methods
}

 

分享到:
评论

相关推荐

    lets-hotfix:Dynamic class reloading for java。Java代码热更新,支持本地、远程

    Class hot reload for java Java代码热更新工具,节省宝贵开发时间 一、背景 在平时的开发过程中,开发流程一般是,编写/修改代码 -> 编译/打包 -> 部署/重启服务 -> 测试刚才的代码 -> 编写/修改代码 -> 编译/打包....

    cas-addon-spring-resource-reloading-support:与处理 Spring Framework 资源运行时重新加载有关的常用实用程序

    cas-addon-spring-resource-reloading-support 该项目是作为 Unicon一部分开发的。 提供此模块的专业支持/集成协助。 欲了解更多信息,。 与在 CAS 服务器的上下文中处理 Spring Framework 资源运行时重新加载有关...

    django-master-class

    Combined with AJAX, it allows for dynamic interactions without reloading the entire page. **Key Concepts:** - **Form Validation:** Django automatically validates forms based on defined fields and ...

    react-scripts-hot-reloading-raw-loader

    热加载原始加载器内容的v4回归 // eslint-disable-next-line import/no-webpack-loader-syntaximport html from '!raw-loader!./example.html'document . body . innerHTML = html 更改example.html会触发react-...

    java class reload

    3. **Tomcat自带的Class reloading** - Tomcat在开发模式下,可以通过设置`reloadable=true`在`conf/server.xml`中的`Context`元素内,启用类的热重载。但这仅适用于源代码改变后,重新编译并部署的 `.class` 文件...

    spark-resource-loading:用于同步资源文件夹中所做更改的 Spark Java 插件

    用法将以下依赖项添加到您的pom.xml : <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-resource-reloading</artifactId> <version>1.0.0</version></dependency>将以下内容添加到您的主要方法中...

    EhLib_9.1.038_for_D7-XE10.2_Full_Source

    + Auto-save PivotGrid layout when reloading data + Showing / hiding total rows/columns in PivotGridEh + New aggregate functions in PivotGridEh (Product, StDev, StDevp, Var, Varp) + Editing Cells in ...

    通过自定义Gradle插件修改编译后的class文件

    在Java开发中,Gradle是一种广泛应用的构建自动化工具,它允许开发者通过编写Groovy或Kotlin DSL脚本来管理项目的构建过程。自定义Gradle插件是Gradle的强大特性之一,可以扩展其功能以满足特定项目需求。本篇将详细...

    Bochs - The cross platform IA-32 (x86) emulator

    - Implemented VMX controls for loading/storing of MSR_PAT and MSR_EFER - Enabled/Implemented secondary proc-based vmexec controls: - Implemented APIC virtualization - Implemented Extended Page ...

    es6-sass-hotreloading-docker-wordpress-theme:ES6 + SASS +热重载+ Docker + WordPress主题

    ES6 + SASS +热重载+ Docker + WordPress主题“主题”-大空白 具有大量开发功能的WordPress快速入门空白模板。 :warning: 警告我为自己创建了这个文件,因此它将不可避免地缺少您需要的东西,为此,我只能道歉并鼓励...

    Artech House - SMS and MMS Interworking in Mobile Networks

    6.2.3 Billing Coherence: Dynamic Originating SMSC GT 111 6.2.4 Use of a Local Virtual SMSC GT in the SIM Card 111 6.3 Detailed Implementation of the Virtual SMSC 112 6.3.1 Half-SCCP Roaming for SMS-MO...

    Script Inspector 3 v3.0.30

    Thanks to its novel approach to code analysis (a hybrid of .Net’s Reflection and incremental syntactic and semantic analysis techniques) Si3 can easily outperform any other IDE (yes, including ...

    C8051F410定时器程序

    at 12MHz with a prescaler of 1:8 and reloading the // T0 registers with TIMER0_RELOAD_HIGH/LOW it will interrupt and then toggle // the LED aproximately one time every second. // // Note: The Timer0 ...

    play-asset-reloading:尝试在存在 sbt-digest Web 插件的情况下重现资产重新加载的问题

    在“play-asset-reloading-master”这个压缩包中,可能包含了一个示例项目,用于展示这个问题的具体情况。通过分析项目源代码、构建配置(如`build.sbt`)以及任何日志输出,我们可以进一步诊断问题的根源。同时,...

    Turbo C++ 3.0[DISK]

    unloading and reloading. (Please see UTIL.DOC for details.) NEW BGI FONTS ------------- Several new fonts have been added to the Borland Graphics Interface: Name Value Description --------------...

    Turbo C++ 3.00[DISK]

    unloading and reloading. (Please see UTIL.DOC for details.) NEW BGI FONTS ------------- Several new fonts have been added to the Borland Graphics Interface: Name Value Description --------------...

    react-hot-service:中间件注入器,使您的expressServer可以热交换支持ES6 +的react-components

    将此服务添加到您的快速应用中以启用react-hot-module-reloading import { reactHotService } from 'react-hot-service' const loaders = { /*...*/ } ; const webpackConf = { "context" : __dirname , "devtool...

    ImpREC 1.7c

    - Fixed bug when loading imports file which contains Exact Call with ordinal - Debug stub scheme added (for getting API from an executable which was compiled in debug mode) - Full Dump (can dump ...

    jrebel6.4.3破解独立java程序可用版本

    从eclipse和网上找到的破解包提取打包成无依赖,独立java程序可用的版本。...2016-07-13 11:43:32 JRebel: Reloading class 'xxxxx'. 2016-07-13 11:43:32 JRebel: Reconfiguring bean 'xxxxx' [xxxxx]

Global site tag (gtag.js) - Google Analytics