1、得到和修改本类的加载器
CLASSPATH指定的所有jar或目录采用AppClassLoader加载器加载
package com.xiaozhi.loader;
public class LoaderTest {
public static void main(String[] args) {
System.out.println(LoaderTest.class.getClassLoader().getClass().getName());
}
}
修改类加载器:将这个类打包成jar文件导出到jdk/jre/lib/ext目录下
运行结果变为
______________________________________________________________________________________________________
2、类加载器之间的父子关系以及管辖范围(类加载器采用委托机制)
运行程序,会出项null指针异常,这是因为第一个类加载器是BootStrap是C++代码写的。
package com.xiaozhi.loader;
public class LoaderTest {
public static void main(String[] args) {
System.out.println(System.class.getClassLoader().getClass().getName());
}
}
package com.xiaozhi.loader;
public class LoaderTest {
public static void main(String[] args) {
ClassLoader loader=LoaderTest.class.getClassLoader();
while(loader!=null){
System.out.println(loader.getClass().getName());
loader=loader.getParent();
}
}
}
______________________________________________________________________________________________________
3、自己动手写类加载器实现加密功能:生成加密class文件,复制到原目录下,AppClassLoader加载出错
首先写一个过会加载器用来加载的类:
package com.xiaozhi.myclassloader;
public class ClassLoaderAttachment {
@Override
public String toString() {
return "hello heima";
}
}
测试类:
package com.xiaozhi.testmyclassloader;
import com.xiaozhi.myclassloader.ClassLoaderAttachment;
public class Test {
public static void main(String[] args) {
System.out.println(new ClassLoaderAttachment().toString());
}
}
其次写一个能加密的类加载器:
package com.xiaozhi.myclassloader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class MyClassLoader {
public static void main(String[] args) throws Exception{
String srcPath = args[0];
String destPah = args[1];
String fileName = srcPath.substring(srcPath.lastIndexOf("\\") + 1);
destPah = destPah +"\\"+fileName;
FileInputStream fileInputStream = new FileInputStream(srcPath);
FileOutputStream fileOutputStream = new FileOutputStream(destPah);
encrypt(fileInputStream, fileOutputStream);
}
public static void encrypt(FileInputStream fileInputStream,FileOutputStream fileOutputStream) throws Exception
{
int b = 0;
while((b=fileInputStream.read())!=-1)
{
fileOutputStream.write(b^0xff);
}
fileInputStream.close();
fileOutputStream.close();
}
}
在项目下新建mylib文件夹(用来存放加密的class文件),然后Run Configurations进入以下界面
运行完后,在mylib上按F5刷新,将生成的class文件,复制到原class文件存放处。再次运行测试类。报错,说明加密成功。
4、自己动手写类加载器:覆盖findClass(String name)方法,删除原目录下的加密的class文件
(1)、要想实现自己的类加载器能够加载类,需要覆盖findClass(String name)方法,因为类加载器的loadClass(String name)方法最终调用的还是findClass(String name)。
(2)、由于类加载器使用的委托机制,先看父类AppClassLoader能不能加载再看自己的类加载器能不能加载,所以要把原目录下刚才拷贝的class字节码文件删除,让自己写的类加载器加载。
下面是自己写的类加载器,具有加密功能
package com.xiaozhi.myclassloader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader{
public static void main(String[] args) throws Exception{//生成加密字节码文件
String srcPath = args[0];
String destPah = args[1];
String fileName = srcPath.substring(srcPath.lastIndexOf("\\") + 1);
destPah = destPah +"\\"+fileName;
FileInputStream fileInputStream = new FileInputStream(srcPath);
FileOutputStream fileOutputStream = new FileOutputStream(destPah);
encrypt(fileInputStream, fileOutputStream);
fileInputStream.close();
fileOutputStream.close();
}
private String classDir;
public MyClassLoader(){
}
public MyClassLoader(String classDir){
this.classDir=classDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {//父类AppClassLoader先找,找不到,子类MyClassLoader再找
String classFileName =classDir+"\\"+name.substring(name.lastIndexOf('.')+1)+".class";
try {
FileInputStream fileInputStream = new FileInputStream(classFileName);
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
encrypt(fileInputStream, arrayOutputStream);
fileInputStream.close();
byte[] bytes = arrayOutputStream.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}
public static void encrypt(InputStream inputStream,OutputStream outputStream) throws Exception
{
int b = 0;
while((b=inputStream.read())!=-1)
{
outputStream.write(b^0xff);
outputStream.flush();
}
}
}
类加载器需要加载的类,继承于Date,
package com.xiaozhi.myclassloader;
import java.util.Date;
public class ClassLoaderAttachment extends Date{
@Override
public String toString() {
return "hello heima";
}
}
测试类
package com.xiaozhi.testmyclassloader;
import java.util.Date;
import com.xiaozhi.myclassloader.MyClassLoader;
public class Test {
public static void main(String[] args) throws Exception{
Class clazz=new MyClassLoader("mylib").loadClass("com.xiaozhi.myclassloader.ClassLoaderAttachment");
// ClassLoaderAttachment loaderAttachment= (ClassLoaderAttachment) clazz.newInstance();//这里不能这样写,因为class文件已经删除,编译器找不到Class文件。
Date date=(Date) clazz.newInstance();
System.out.println(date);
}
}
运行结果
把加密的class复制到原class目录下
运行程序:
找到需要类加载器需要加载的类,敲一个回车,保存一下,生成新的class文件
再次运行
再次把这个新生出的class文件删了
再次运行
5、类加载器的高级问题解决
(1)、编写一个能打印自己的类加载器名称和当前类加载器的父子结构关系链的Servlet,正常发布后,能看到打印结果,第一个加载器是WebAppClassLoader。
(2)、把该Servlet的class文件打成jar包,放到ext目录下,重启tomcat,发现报找不到
HttpServlet的错误。
(3)、把servlet-api.jar也放到ext目录下,问题解决,打印结果为WxtClassLoader。
servlet代码
package xom.xiaozhi.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
ClassLoader classLoader= this.getClass().getClassLoader();
while(classLoader!=null){
out.println(classLoader.getClass().getName()+"<br>");
classLoader=classLoader.getParent();
}
out.close();
}
}
运行结果:
打成jar放在ext目录下
再次运行程序
再把tomcat下的servlet-api.jar拷贝到ext目录下
运行程序
---------------------- ASP.Net+Unity开发、 .Net培训、期待与您交流! ----------------------