JVM类加载器

一:类加载器的层次结构
	1、引导类加载器:用来加载java的核心库。
	2、扩展类加载器:用来加载java的扩展库。实现类:sun.misc.Launcher$ExtClassLoader
	3、应用类加载器:加载本应用所需要的类。实现类:sun.misc.Launcher$AppClassLoader
	4、自定义类加载器
	注意:1-4依次是后者的父类,但不是通过继承来实现的,而是通过组合来实现的
		  1不是用java实现的,而是用c语言,后面三者都是用java语言实现的,都实现了java.lang.ClassLoader类


二:类加载采用代理模式
	一般的类加载使用双亲委托机制,这样做主要是为了安全。如程序员定义的java.lang.String永远都不能被加载。
	并不是所有的都是使用双亲委托机制。
	
三:ClassLoader常用方法:
	getParent() 
	loadClass(String name) 
	findClass(String name) 
	findLoadedClass(String name) 
	defineClass(String name, byte[] b, int off, int len) 
	resolveClass(Class<?> c) 
	
四:自定义类加载器
	继承java.lang.ClassLoader 重写findClass(String name)方法
	1、文件类自定义加载器
	2、网络类自定义加载器
	两者操作差不多,只是.class文件源头一个来自于文件,一个来自于url指定的服务器。	
	加密的类加载器:就是用一定的算法,先对.class文件进行加密操作,然后用相应的解密算法解密并进行类加载。
	注意:同一个类被同一个类加载器加载会得到相同的Class对象
		  同一个类被不同的类加载器加载会得到不同的Class对象
	
五:系统默认的类加载器是双亲委托机制,但并不是所有的类都要使用这种机制,如TOMCAT服务器就开始默认的类加载机制
	而是使用自定义的类加载机制。
	线程上线文类加载器,就可以用来获得当前线程的类加载器、修改当前线程的类加载器
	Thread.currentThread().getContextClassLoader()获得当前线程的类加载器
	Thread.currentThread().setContextClassLoader()设置当前线程的类加载器
1、文件类加载器:
package com.chen.File;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 自定义类加载器
 * 1、文件类加载器
 * @author CHJ
 *
 */
public class FileSystemClassLoader extends ClassLoader{

	// 加载路径。如:F:/New 中的  com.chen.Base_Points.First.class
	private String rootDir;
	
	public FileSystemClassLoader(String rootDir) {
		
		this.rootDir = rootDir;
	}
	
	//重写方法
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		
		Class<?> c = findLoadedClass(name);
		
		if(c != null) {
			
			return c;
		}else{
			
			// 这里为了简单不使用双亲委托模式
			byte[] classData = getClassData(name);
			if(classData == null) {
				
				throw new ClassNotFoundException();
			}else{
				
				c = defineClass(name, classData, 0, classData.length);// defineClass为ClassLoader中的方法
			}
		}
		
		return c;
	}

	/**
	 * 将制定的.class文件写入字节数组中
	 * @param name
	 * @return
	 */
	private byte[] getClassData(String name) {
		
		// 拼出.class文件的完整路径
		String path = rootDir + "/" + name.replace('.', '/') + ".class";
		InputStream is = null;
		ByteArrayOutputStream bos = null;
		try {
			 
			is = new FileInputStream(path);
			bos = new ByteArrayOutputStream();
			
			
			byte[] buffer = new byte[1024];
			int len = 0;
			while((len = is.read(buffer)) != -1){
				
				bos.write(buffer, 0, len);
			}
			bos.flush();
			
			return bos.toByteArray();
		} catch (Exception e) {
			
			
			e.printStackTrace();
			return null;
		}finally{
			
			try {
				if(is != null) {
					
					is.close();
				}
				
				if(is != null) {
					
					bos.close();
				}
			} catch (IOException e) {
				
				e.printStackTrace();
			}
			
		}
		
	}
}

package com.chen.File;

public class Test {

	public static void main(String[] args) throws Exception {
		
		FileSystemClassLoader loader = new FileSystemClassLoader("F:/New");
		FileSystemClassLoader loader2 = new FileSystemClassLoader("F:/New");

		Class<?> c1 = loader.loadClass("com.chen.Base_Points.First");
		Class<?> c2 = loader.loadClass("com.chen.Base_Points.First");
		Class<?> c3 = loader2.loadClass("com.chen.Base_Points.First");
		
		Class<?> c4 = loader.loadClass("java.lang.String");
		
		System.out.println(c1.hashCode());
		System.out.println(c2.hashCode());// 同一个.class文件被同一个类加载器加载生成同一个Class对象
		System.out.println(c3.hashCode());// 同一个.class文件被不同的类加载加载生成不同的Class对象
		
		System.out.println(c1.getClassLoader());// 用自定义类加载器加载的
		System.out.println(c4.getClassLoader());// 返回值为lang用引导构造器加载的
		
		
	}
}

2、加密型文件类加载器:
加密算法:
package com.chen.File_Encryption;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 简单的加密工具(取反操作)
 * @author Administrator
 *
 */
public class EncryptionUtil {

	
	/**
	 * 演示取反
	 * @param args
	 */
	public static void main(String[] args) {
		
		int a = 3;// 二进制为00000011
		// 转换成二进制
		System.out.println(Integer.toBinaryString(a));// 11
		// 取反(做异或运算)
		System.out.println(Integer.toBinaryString(a^0xff));// 11111100
	}
	
	
	/**
	 * 加密方法:把一个文件中二进制全部取反
	 * @param src
	 * @param dest
	 */
	public static void Encryption(String src, String dest) {
		
		InputStream is = null;
		OutputStream os = null;
		
		try {
			is = new FileInputStream(src);
			os = new FileOutputStream(dest);
			
			int temp = -1;
			while((temp = is.read()) != -1){
				
				os.write(temp^0xff);// 取反操作
			}
			os.flush();
			
		} catch (Exception e) {
			
			e.printStackTrace();
		}finally{
			
			if(is != null){
				
				try {
					is.close();
				} catch (IOException e) {
					
					e.printStackTrace();
				}
			}
			
			if(os != null){
				
				try {
					os.close();
				} catch (IOException e) {
					
					e.printStackTrace();
				}
			}
		}
		
	}
}

加密类加载器:

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 与加密类加载器相对应的解密类加载器
 * @author CHJ
 *
 */
public class DeEncryptonClassLoader extends ClassLoader {

	// 加载路径。如:F:/New 中的  com.chen.Base_Points.First.class
		private String rootDir;
		
		public DeEncryptonClassLoader(String rootDir) {
			
			this.rootDir = rootDir;
		}
		
		//重写方法
		@Override
		protected Class<?> findClass(String name) throws ClassNotFoundException {
			
			Class<?> c = findLoadedClass(name);
			
			if(c != null) {
				
				return c;
			}else{
				
				// 这里为了简单不使用双亲委托模式
				byte[] classData = getClassData(name);
				if(classData == null) {
					
					throw new ClassNotFoundException();
				}else{
					
					c = defineClass(name, classData, 0, classData.length);// defineClass为ClassLoader中的方法
				}
			}
			
			return c;
		}

		/**
		 * 将制定的.class文件写入字节数组中
		 * @param name
		 * @return
		 */
		private byte[] getClassData(String name) {
			
			// 拼出.class文件的完整路径
			String path = rootDir + "/" + name.replace('.', '/') + ".class";
			InputStream is = null;
			ByteArrayOutputStream bos = null;
			try {
				 
				is = new FileInputStream(path);
				bos = new ByteArrayOutputStream();
				
				/*
				byte[] buffer = new byte[1024];
				int len = 0;
				while((len = is.read(buffer)) != -1){
					
					bos.write(buffer, 0, len);
				}
				bos.flush();
				
				return bos.toByteArray();
				*/
				
				int temp = -1;
				while((temp = is.read()) != -1) {
					
					bos.write(temp^0xff);// 取反
				}
				bos.flush();
				
				return bos.toByteArray();
			} catch (Exception e) {
				
				
				e.printStackTrace();
				return null;
			}finally{
				try{
					if(is != null) {
						
						is.close();
					}
					
					if(is != null) {
						
						bos.close();
					}
				} catch (IOException e) {
					
					e.printStackTrace();
				}
				
			}
			
		}

}
</pre><pre name="code" class="java">

public class Test {

	public static void main(String[] args) throws Exception {
		
		EncryptionUtil.Encryption("F:/New/HelloWorld.class", "F:/New/temp/HelloWorld.class");
		System.out.println("加密成功");
		
		// 用原来的类加载器加载加密的.class文件会报ClassFormatError
		//FileSystemClassLoader loader = new FileSystemClassLoader("F:/New/temp");
		//Class<?> c = loader.loadClass("HelloWorld");
		
		
		// 下面使用解密的类加载器进行加载
		
		// 注意:这里的.class文件是我用记事本写的,不导入任何包。如果加载的.class文件中有import..,注意导入需要的包,还要注意路径
		DeEncryptonClassLoader loader = new DeEncryptonClassLoader("F:/New/temp");
		Class<?> c = loader.loadClass("HelloWorld");
		System.out.println(c.getClassLoader());
	}
}



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值