博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Internals of Java Class Loading 3
阅读量:6679 次
发布时间:2019-06-25

本文共 8398 字,大约阅读时间需要 27 分钟。

hot3.png

Custom Class Loaders

The solution to fine-control class loading is to implement custom class loaders. Any custom class loader should have java.lang.ClassLoader as its direct or distant super class. Moreover, in the constructor, we need to set the parent class loader, too. Then, we have to override the findClass() method. The differentversionspush folder contains a custom class loader called FileSystemClassLoader. Its structure is shown in Figure 9:

Figure 9. Custom class loader relationship

Below are the main methods implemented in common.FileSystemClassLoader:

public byte[] findClassBytes(String className){        try{            String pathName = currentRoot +                File.separatorChar + className.                replace('.', File.separatorChar)                + ".class";            FileInputStream inFile = new                FileInputStream(pathName);            byte[] classBytes = new                byte[inFile.available()];            inFile.read(classBytes);            return classBytes;        }        catch (java.io.IOException ioEx){            return null;        }    }    public Class findClass(String name)throws        ClassNotFoundException{        byte[] classBytes = findClassBytes(name);        if (classBytes==null){            throw new ClassNotFoundException();        }        else{            return defineClass(name, classBytes,                0, classBytes.length);        }    }    public Class findClass(String name, byte[]        classBytes)throws ClassNotFoundException{        if (classBytes==null){            throw new ClassNotFoundException(                "(classBytes==null)");        }        else{            return defineClass(name, classBytes,                0, classBytes.length);        }    }    public void execute(String codeName,        byte[] code){        Class klass = null;        try{            klass = findClass(codeName, code);            TaskIntf task = (TaskIntf)                klass.newInstance();            task.execute();        }        catch(Exception exception){            exception.printStackTrace();        }    }

This class is used by the client to convert the client.TaskImpl(v1) to a byte[]. This byte[] is then send to the RMI Server Execution Engine. In the server, the same class is used for defining the class back from the code in the form of byte[]. The client-side code is shown below:

public class Client{    public static void main (String[] args){        try{            byte[] code = getClassDefinition                ("client.TaskImpl");            serverIntf.execute("client.TaskImpl",                code);            }            catch(RemoteException remoteException){                remoteException.printStackTrace();            }        }    private static byte[] getClassDefinition        (String codeName){        String userDir = System.getProperties().            getProperty("BytePath");        FileSystemClassLoader fscl1 = null;        try{            fscl1 = new FileSystemClassLoader                (userDir);        }        catch(FileNotFoundException            fileNotFoundException){            fileNotFoundException.printStackTrace();        }        return fscl1.findClassBytes(codeName);    }}

Inside of the execution engine, the code received from the client is given to the custom class loader. The custom class loader will define the class back from the byte[], instantiate the class, and execute. The notable point here is that, for each client request, we use separate instances of the FileSystemClassLoader class to define the client-supplied client.TaskImpl. Moreover, the client.TaskImpl is not available in the class path of the server. This means that when we call findClass() on theFileSystemClassLoader, the findClass() method calls defineClass() internally, and the client.TaskImpl class gets defined by that particular instance of the class loader. So when a new instance of the FileSystemClassLoader is used, the class is defined from the byte[] all over again. Thus, for each client invocation, class client.TaskImpl is defined again and again and we are able to execute "different versions" of the client.TaskImpl code inside of the same Execution Engine JVM.

public void execute(String codeName, byte[] code)throws RemoteException{        FileSystemClassLoader fileSystemClassLoader = null;        try{            fileSystemClassLoader = new FileSystemClassLoader();            fileSystemClassLoader.execute(codeName, code);        }        catch(Exception exception){            throw new RemoteException(exception.getMessage());        }    }

Examples are in the differentversionspush folder. The server and client side consoles are shown in Figures 10, 11, and 12:

Figure 10. Custom class loader execution engine

Figure 10 shows the custom class loader Execution Engine VM console. We can see the client.TaskImpl code is loaded more than once. In fact, for each client execution context, the class is newly loaded and instantiated.

Figure 11. Custom class loader engine, Client 1

In Figure 11, the code for the TaskImpl class containing the log statement client.TaskImpl.class.getClassLoader(v1) is loaded by the client VM, and pushed to the Execution Engine Server VM. The client VM in Figure 12 loads a different code for the TaskImpl class containing the log statementclient.TaskImpl.class.getClassLoader(v2), and pushes to the Server VM.

Figure 12. Custom class loader engine, Client 2

This code example shows how we can leverage separate instances of class loaders to have side-by-side execution of "different versions" of code in the same VM.

Class Loaders In J2EE

The class loaders in some J2EE servers tend to drop and reload classes at different intervals. This will occur in some implementations and may not on others. Similarly, a web server may decide to remove a previously loaded servlet instance, perhaps because it is explicitly asked to do so by the server administrator, or because the servlet has been idle for a long time. When a request is first made for a JSP (assuming it hasn't been precompiled), the JSP engine will translate the JSP into its page implementation class, which takes the form of a standard Java servlet. Once the page's implementation servlet has been created, it will be compiled into a class file by the JSP engine and will be ready for use. Each time a container receives a request, it first checks to see if the JSP file has changed since it was last translated. If it has, it's retranslated so that the response is always generated by the most up-to-date implementation of the JSP file. Enterprise application deployment units in the form of .ear, .war, .rar, etc. will also needs to be loaded and reloaded at will or as per configured policies. For all of these scenarios, loading, unloading and reloading is possible only if we have control over the application server's JVM's class-loading policy. This is attained by an extended class loader, which can execute the code defined in its boundary. Brett Peterson has given an explanation of class loading schemas in a J2EE application server context in his article "" at .

Summary

The article talked about how classes loaded into a Java virtual machine are uniquely identified and what limitations exist when we try to load different byte codes for classes with the same names and packages. Since there is no explicit class versioning mechanism, if we want to load classes at our own will, we have to use custom class loaders with extended capabilities. Many J2EE application servers have a "hot deployment" capability, where we can reload an application with a new version of class definition, without bringing the server VM down. Such application servers make use of custom class loaders. Even if we don't use an application server, we can create and use custom class loaders to finely control class loading mechanisms in our Java applications. Ted Neward's book  throws light onto the ins and outs of Java class loading, and it teaches those concepts of Java that underlie the J2EE APIs and the best ways to use them.

References

  •  for this article
  • The 
  • "" in the Java tutorial
  • "" from 
  • "" from 
  • "" from 
  • "" from 
  •  by Ted Neward

 is a Senior Technical Architect at Communication Service Providers Practice (CSP) of , and is a Sun Microsystems Certified Enterprise Architect and a Microsoft Certified Professional.

转载于:https://my.oschina.net/u/138995/blog/177296

你可能感兴趣的文章
loadrunner如何监控windows,以及重点指标分析
查看>>
内置数据结构(1)
查看>>
2017云计算热点回顾:拓展云边界 决胜智能云
查看>>
linux下使用lftp的小结
查看>>
面试敲门砖
查看>>
python将日志导入数据库代码案例2
查看>>
ORA-12705: Cannot access NLS data files or invalid environment specified
查看>>
用 Python 脚本实现对 Linux 服务器的监控
查看>>
windows主机安装zabbix-agent
查看>>
VirtualEnv 和Pip 构建Python的虚拟工作环境
查看>>
NetScaler的部署实验之四更新DDC的SSL证书配置及NetScaler对DDC的负载均衡配置
查看>>
cisco数据中心理论小记-3
查看>>
安装及配置php并发布phpmyadmin网站
查看>>
一个会展论坛进行的全息营销“策划” -王甲佳全息营销系列08
查看>>
JQuery选择器——子元素筛选选择器和表单元素选择器
查看>>
zabbix调试报错汇总
查看>>
在Nginx中部署基于IP的虚拟主机
查看>>
uml绘制类图
查看>>
nginx的location优先级
查看>>
晕,CCNP升级了
查看>>