1). 模拟实现Tomcat的webappClassLoader加载自己war包应用内不同版本类实现相互共存与隔离

    1. package com.tuling.jvm;
    2. import java.io.FileInputStream;
    3. import java.lang.reflect.Method;
    4. public class MyClassLoaderTest {
    5. static class MyClassLoader extends ClassLoader {
    6. private String classPath;
    7. public MyClassLoader(String classPath) {
    8. this.classPath = classPath;
    9. }
    10. private byte[] loadByte(String name) throws Exception {
    11. name = name.replaceAll("\\.", "/");
    12. FileInputStream fis = new FileInputStream(classPath + "/" + name
    13. + ".class");
    14. int len = fis.available();
    15. byte[] data = new byte[len];
    16. fis.read(data);
    17. fis.close();
    18. return data;
    19. }
    20. protected Class<?> findClass(String name) throws ClassNotFoundException {
    21. try {
    22. byte[] data = loadByte(name);
    23. return defineClass(name, data, 0, data.length);
    24. } catch (Exception e) {
    25. e.printStackTrace();
    26. throw new ClassNotFoundException();
    27. }
    28. }
    29. /**
    30. * 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载
    31. */
    32. protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    33. synchronized (getClassLoadingLock(name)) {
    34. // First, check if the class has already been loaded
    35. Class<?> c = findLoadedClass(name);
    36. if (c == null) {
    37. // If still not found, then invoke findClass in order
    38. // to find the class.
    39. long t1 = System.nanoTime();
    40. //非自定义的类还是走双亲委派加载
    41. if (!name.startsWith("com.tuling.jvm")) {
    42. c = this.getParent().loadClass(name);
    43. } else {
    44. c = findClass(name);
    45. }
    46. // this is the defining class loader; record the stats
    47. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
    48. sun.misc.PerfCounter.getFindClasses().increment();
    49. }
    50. if (resolve) {
    51. resolveClass(c);
    52. }
    53. return c;
    54. }
    55. }
    56. }
    57. public static void main(String args[]) throws Exception {
    58. MyClassLoader classLoader = new MyClassLoader("D:/test");
    59. Class clazz = classLoader.loadClass("com.tuling.jvm.User");
    60. Object obj = clazz.newInstance();
    61. Method method = clazz.getDeclaredMethod("sout", null);
    62. method.invoke(obj, null);
    63. System.out.println(clazz.getClassLoader());
    64. System.out.println();
    65. MyClassLoader classLoader1 = new MyClassLoader("D:/test1");
    66. Class clazz1 = classLoader1.loadClass("com.tuling.jvm.User");
    67. Object obj1 = clazz1.newInstance();
    68. Method method1 = clazz1.getDeclaredMethod("sout", null);
    69. method1.invoke(obj1, null);
    70. System.out.println(clazz1.getClassLoader());
    71. }
    72. }

    2).User类,往D:/test和D:/test1中分别放两个包名一样、类名一样的类User,只sout函数的打印信息不一样。

    1. package com.tuling.jvm;
    2. public class User {
    3. private int id;
    4. private String name;
    5. public User() {
    6. }
    7. public User(int id, String name) {
    8. super();
    9. this.id = id;
    10. this.name = name;
    11. }
    12. public int getId() {
    13. return id;
    14. }
    15. public void setId(int id) {
    16. this.id = id;
    17. }
    18. public String getName() {
    19. return name;
    20. }
    21. public void setName(String name) {
    22. this.name = name;
    23. }
    24. public void sout() {
    25. System.out.println("=======自己的加载器加载类调用方法=======");
    26. }
    27. }

    3).结果
    image.png