首先介绍自定义类的应用场景:

(1)加密:Java代码可以轻易的被反编译,如果你需要把自己的代码进行加密以防止反编译,可以先将编译后的代码用某种加密算法加密,类加密后就不能再用Java的ClassLoader去加载类了,这时就需要自定义ClassLoader在加载类的时候先解密类,然后再加载。

(2)从非标准的来源加载代码:如果你的字节码是放在数据库、甚至是在云端,就可以自定义类加载器,从指定的来源加载类。

(3)以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理。这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着进行解密和验证,最后定义出在Java虚拟机中运行的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.test6;
 
public class DataInfo {
 
    private Long id;
 
    private String userName;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getUserName() {
        return userName;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    @Override
    public String toString() {
        return "DataInfo [id=" 1 ", userName=" "测试" "]";
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.test6;
 
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
 
/**
 * 自定义加载器
 
 * @author sdc
 *
 */
public class MySelfClassLoader extends ClassLoader {
 
    public MySelfClassLoader() {
 
    }
 
    public MySelfClassLoader(ClassLoader parent) {
        super(parent);
    }
 
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        File file = new File("D:/DataInfo.class");
 
        try {
            byte[] bytes = getClassBytes(file);
            // defineClass方法可以把二进制流字节组成的文件转换为一个java.lang.Class
            Class<?> cla = this.defineClass(name, bytes, 0, bytes.length);
            return cla;
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return super.findClass(name);
    }
 
    private byte[] getClassBytes(File file) throws Exception {
        // 这里要读入.class的字节,因此要使用字节流
        FileInputStream fis = new FileInputStream(file);
        FileChannel fc = fis.getChannel();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        WritableByteChannel wbc = Channels.newChannel(baos);
        ByteBuffer by = ByteBuffer.allocate(1024);
 
        while (true) {
            int i = fc.read(by);
            if (i == 0 || i == -1)
                break;
            by.flip();
            wbc.write(by);
            by.clear();
        }
        fis.close();
        return baos.toByteArray();
    }
 
    public static void main(String[] args) {
 
        MySelfClassLoader mcl = new MySelfClassLoader();
        Class<?> clazz;
        try {
            clazz = Class.forName("DataInfo"true, mcl);
            Object obj = clazz.newInstance();
 
            System.out.println(obj);
            System.out.println(obj.getClass().getClassLoader());// 打印出我们的自定义类加载器
        catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
 
}