JVM类加载机制以及类缓存问题的处理(2)

package com.linuxidc.utils; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; public class ServiceClassLoader extends ClassLoader{ private String classPath; public ServiceClassLoader(String classPath) { this.classPath = classPath; } /** * 重写父类的findClass 方法。 父类的loadClass会调用此方法 */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = null; byte[] classData = getClassData(name); if (classData!=null) { c = defineClass(name, classData, 0, classData.length); }else { throw new ClassNotFoundException(); } return c; }   
  
   // 将class文件通过IO流读取,转化为字节数组
private byte[] getClassData(String name) { String path = classPath + "/"+ name.replace('.', '/') + ".class"; InputStream iStream = null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { iStream = new FileInputStream(path); byte[] buffer = new byte[1024]; int temp = 0; while ((temp = iStream.read(buffer))!=-1) { byteArrayOutputStream.write(buffer, 0, temp); } if (byteArrayOutputStream!=null) { return byteArrayOutputStream.toByteArray(); } } catch (Exception e) { e.printStackTrace(); }finally { try { if (iStream!=null) { iStream.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (byteArrayOutputStream!=null) { byteArrayOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } }

  对类加载器的使用代码如下:

ServiceClassLoader serviceClassLoader = new ServiceClassLoader("c:\myclass"); Czlass<?> c = ServiceClassLoader.loadClass("com.linuxidc.service.Myclass");

  如果用同一个ServiceClassLoader对象去加载同一个Class文件多次,每次加载后的Class对象为同一个! 然而如果new不同的自定义ClassLoader去加载同一个Class文件,则每次会返回不同的Class对象。

  注意:不能将所要加载的Class文件放到classpath目录及其任何子目录下,否则会被AppClassLoader优先加载(这是由于类加载采用双亲委派机制,同时AppClassLoader可以加载所有在classpath下的class文件),每次都是同一个AppClassLoader进行加载,因此会出现类缓存问题。

  这样就解决了通常在JVM类加载时,直接使用反射出现的类缓存的问题。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/5268c91b05af2e4ac8a09de4296ada52.html