09 类加载案例与实战

Wu Jun 2020-01-09 20:44:19
05 Java > 01 Java 虚拟机

1 案例分析

1.1 Tomcat:正统的类加载器架构

image

1.2 OSGI:灵活的类加载架构

image

1.3 字节码生成技术与动态代理的实现

public class DynamicProxyTest {
       interface IHello {
             void sayHello();
       }

       static class Hello implements IHello {
             @Override
             public void sayHello() {
                    System.out.println("Hello world");
             }
       }

       static class DynamicProxy implements InvocationHandler {
             Object originalObj;

             Object bind(Object originalObj) {
                    this.originalObj = originalObj;
                    return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(),
                                 originalObj.getClass().getInterfaces(), this);
             }

             @Override
             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("Welcome");
                    return method.invoke(originalObj, args);
             }
       }

       public static void main(String[] args) {
             // add this property to generate proxy class file
              System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
             IHello hello = (IHello) new DynamicProxy().bind(new Hello());
             hello.sayHello();
       }
}

1.4 Retrotranslator:跨越 JDK 版本

2 实战:自己动手实现远程执行功能

2.1 目标

不依赖 JDK 版本、不改变原有服务端程序的部署,不依赖任何第三方类库、不侵入原有程序、临时代码的执行结果能返回到客户端;

2.2 思路

2.3 具体实现

public class JavaClassExecutor {
       public static String execute(byte[] classByte) {
             HackSystem.clearBuffer();
             ClassModifier cm = new ClassModifier(classByte);
             byte[] modifiedBytes = cm.modifyUTF8Constant("java/lang/System",
                           "org/fenixsoft/classloading/execute/HackSystem");
             HotSwapClassLoader hotSwapClassLoader = new HotSwapClassLoader();
             Class clazz = hotSwapClassLoader.loadByte(modifiedBytes);
             try {
                    Method method = clazz.getMethod("main", new Class[] { String[].class });
                    method.invoke(null, new String[] { null });
             } catch (Throwable t) {
                    t.printStackTrace(HackSystem.out);
             }
             return HackSystem.getBufferString();
       }
}

用于测试的JSP

<%@page import="java.lang.*" %>
<%@page import="java.io.*" %>
<%@page import="org.fenixsoft.classloading.execute.*" %>
<%
    InputStream is = new FileInputStream("c:/TestClass.class");
    byte[] b = new byte[is.available()];
    is.read(b);
    is.close();
    out.println(JavaClassExecutor.execute(b));
%>