首页 » 语言&开发 » Java » Java类加载相关学习笔记(2)

Java类加载相关学习笔记(2)

 

上文学习了Java类加载相关基本知识。

本文举例一个简单例子(自定义类加载,加密解密,再通过反射的机制调用)。

其实类似JSP原理

package com.test;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.URL;

/**

*   @author Sahinn

*   @date 16/4/16

*   自定义ClassLoader

*   主要是从网络获取来的字节流,进行某种加密解密之后来创建类对象

*   比如对http://src.zuobin.net/net/zuobin/netclass/decodeTest.class进行加密解密

*   当然可以提供带参数的,校验的,返回class字节流的服务,这样某些代码就可以存放在服务器端

    */

public class NetDecodeClassLoader extends ClassLoader {

    private String netPath;

    private String packageName="net.zuobin.netclass";



    //设置某种加密方式,加密key等

    private String decodeStyle;

    private String decodeKey;



    //配置网络地址

    public NetDecodeClassLoader(String netPath,String decodeStyle,String decodeKey) {

        this.netPath = netPath;

        this.decodeStyle = decodeStyle;

        this.decodeKey = decodeKey;

    }



    protected byte[] deCode(byte[] bytes){

        //进行具体的解密,校验操作等等

        //比如base64等

        return bytes;

    }



    private byte[] getData(String className){



        //可以带验证key,https等等

        String path = this.netPath + File.separator + className.replace('.',File.separatorChar) + ".class";



        try {

            URL url = new URL(path);

            InputStream in = url.openStream();

            OutputStream byteArrayOutputStream = new ByteArrayOutputStream();

            byte[] buffer = new byte[2048];

            int num = 0;



            while ((num = in.read(buffer)) != -1){

                byteArrayOutputStream.write(buffer,0,num);

            }

            return ((ByteArrayOutputStream)byteArrayOutputStream).toByteArray();

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }



    @Override

    protected Class<?> findClass(String name) throws ClassNotFoundException {



        Class<?> aclass =  findLoadedClass(name);



        //查询是否已加载

        if (aclass != null) {

            return aclass;

        }

        //指定具体的包下的类需要从网络里面获取,然后解密

        if (packageName.startsWith(name)) {



            byte[] data = getData(name);



            byte[] decodedata =  this.deCode(data);



            if (decodedata == null) {

                throw new ClassNotFoundException();

            }else {

                return defineClass(name,decodedata,0,decodedata.length);



            }

        }

        //如果不是该包里面的类,直接返回父类的类加载机制

        return super.findClass(name);

    }


}

注意点:

JVM在加载类之前会检查类是否已被加载(findLoadedClass()),如果已被加载再调用loadClass就好出错。

JVM判断类是否是同一个有两个条件

  • 判断类名包名是否是同一个

  • 加载这个ClassLoader的实例对象是否是同一个,注意是实例对象

由于大量使用动态类加载会增加JVM的PermGen区,只有Full GC时候才会被回收。

推荐使用的方式是,动态类加载不保存类对象,创建后就释放掉,这样就不会造成内存溢出了(其实这就是JSP加载机制了)。



原文链接:Java类加载相关学习笔记(2),转载请注明来源!

0