第九章:类加载及执行子系统的案例与实战
在Class文件以何种方式存储,类型何时加载,如何连接,以及虚拟机如何执行字节码指令等都是虚拟机直接控制的行为,用户程序无法进行改变,能通过程序进行操作的,主要是字节码生成与类加载器两部分的功能。
案例分析
Tomcat:正统的类加载器架构
在Tomcat目录结构中有三组目录可以放Java类库,另外再加上Web应用程序自身的目录
- /common/*-类库可以被Tomcat和所有的Web应用程序共同使用
- /server/*-类库可以被Tomcat使用,对所有的Web应用程序不可见
- /shared/*-类可以被所有的Web应用程序共同使用,但是对Tomcat自己不可见
- /WebApp/WEB-INF-类仅仅可以被此Web应用程序使用,对Tomcat和其他的Web应用程序都不可见
Tomcat自定义了多个类加载器,并且按照经典的双亲委派模型来实现
- CommonCLassLoader->/common/*
- CatalinaClassLoader->/server/*
- SharedClassLoader->/shared/*
- WebappClassLoader->/WebApp/WEB-INF/*,每一个Web应用程序对应一个WebApp类加载器,每一个JSP文件对应一个Jsp类加载器
字节码生成技术和动态代理实现
public class DynamicProxyTest {
interface IHello {
void sayHello();
}
static class Hello implements IHello {
@Override
public void sayHello() {
System.out.println("hello world");
}
}
public static class GoodBye implements IHello {
@Override
public void sayHello() {
System.out.println("say goodBye");
}
}
static class DynamicProxy<T> implements InvocationHandler {
T originalObj;
T bind(T originalObj) {
this.originalObj = originalObj;
return (T) 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) {
IHello hello = new DynamicProxy<IHello>().bind(new Hello());
hello.sayHello();
IHello hello2 = new DynamicProxy<IHello>().bind(new GoodBye());
hello2.sayHello();
}
}
}