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

(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();
         }
 
     }
 
}