类加载及执行子系统案例与实战

类加载及执行子系统案例、实战

Tomcat正统的类加载器结构

  • 一个完整的web服务器应具备:

    (1)部署在同一服务器上的不同web程序使用的java类库可实现隔离

    (2)与(1)相反,不同web程序使用的java类库可实现共享,如很多使用spring组织的应用在同一服务器上。

    (3)保证服务器自身安全不受web程序影响。

    (4)hotswap,热替换

  • 综上,部署web程序需要很多classpath。

    在/common目录,类库可被tomcat与所有web程序使用。

    在/server目录,对Tomcat可见,对web程序不可见。

    在/shared目录,对所有web程序可见,对Tomcat不可见。

    在/WebApp/WEB-INF目录,对该web程序可见,对其他web及Tomcat不可见。

  • 由此,Tomcat采用如下类加载器结构:

    启动类加载器bootstrap

    <–扩展加载器extension

    <–程序加载器Application

    <–common加载器<–catalina类加载器(server类加载器)

    ​ <–shared加载器<–WebApp加载器<–Jsp类加载器。

  • Tomcat 6之后,为了增加易用性,将/common /server /shared目录合并为一个/lib目录。

以动态代理理解字节码生成技术

  • 简单的动态代理代码如下:

    package com.sdt;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class Base {
        /**
         * author: abner
         */
        interface Ihello{
            void sayhello();
            void sayyes();
        }
    
        static class Hello implements Ihello{
    
            @Override
            public void sayhello(){
                System.out.println("hello world");
            }
    
            @Override
            public void sayyes(){
                System.out.println("yes");
            }
        }
    
        static class DynamicHello implements InvocationHandler{
            private Object object;
            public Object bind(Object obj){
                object=obj;
                return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
            }
    
            @Override
            public Object invoke(Object proxy, Method method,Object[] args) throws Throwable{
                System.out.println("welcome +");
                return method.invoke(object,args);
            }
        }
    
        public static void main(String[] args) {
            Ihello ihello = (Ihello) new DynamicHello().bind(new Hello());
            ihello.sayhello();
            ihello.sayyes();
            int i = ihello.hashCode();
        }
    }
    

    输出结果:

    welcome +
    hello world
    welcome +
    yes
    welcome +
    

    代码中唯一的黑匣子是

    Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    

    方法,经过层层调用,这个方法产生一个代理类字节码byte数组。经过反编译后可以发现其为ihello对象的每个方法都生成了对应实现并调用了invoke方法。P344.

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

  • 目标:

    不侵入原有程序,不影响原有程序

    临时代码不依赖特定的类或接口。

    临时代码结果要返回客户端。

  • 思路

    在客户端编译好后将字节码发送给服务端执行。

    让类加载器加载上述字节码并能访问到服务端其他类库。

    程序收集标准输出和错误输出的内容,在执行类中把对System.out的符号引用替换为自己的PrintStream。

  • 实现

    P350

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值