提纲
案例
tomcat:正统的类加载器结构
web服务器要解决的问题:
部署在同一个服务器上的两个web应用程序所使用的java类库可以实现相互隔离。
部署在同一个服务器上的两个web应用程序所使用的java类库可以实现共享。
服务器需要尽可能的保证自身的安全不受部署的web应用程序影响。
支持jsp应用的web服务器,大多数需要支持hotspot功能。
java类库放置在tomcat目录含义:
放置在/common中:类库可被tomcat和所有的web应用程序共同使用。
放置在/server中:类库可被tomcat使用,对所有web程序不可见。
放置在/shared中:类库可被所有的web应用程序共同使用,但对tomcat自己不可见
放置在/WebApp/WEB-INF中:类库仅仅可以被此web程序使用,对tomcat和其它web程序都不可见。
OSGI:灵活的类加载器结构
OSGI的bundle类加载器之间只有规则,没有规定的委派关系。
类加载时的查找规则如下:
以java.*开头的类,委派给父类加载器加载。
否则,委派给列表名单内的类,委派给父类加载器加载。
否则,import列表中的类,委派给export这个类的bundle的类加载器加载。
否则,查找当前bundle的classpath,使用自己的类加载器加载。
否则,查找是否在自己的Fragment Bundle中,如果是,则委派给Fragment Bundle的类加载器加载。
否则,查找Dynamic Import列表中的bundle,委派给对应的类加载器加载。
否则,类查找失败。
osgi相关的框架有Equnix、Felix、SpringDM(被卖身了)
示例1--搭建一个简单的osgi项目
1.官网下载felix:http://felix.apache.org/downloads.cgi
2.创建一个java project,将解压后的felix框架复制到project中:
点击Run As->java Application
选择好主类,可以看到控制台成功运行:
3.创建一个plugin-in项目,选择an osgi framework--standard,并下一步:
创建一个简单的示例,Activitor代码为:
public class Activator implements BundleActivator {
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
System.out.println("Hello World!!");
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
System.out.println("Goodbye World!!");
}
}
可以看到Activitor通过实现BundleActivitor来创建自己模块的类加载器。我们点击export--->plugins and fragments:
将该模块导入到我们的felix项目中
导入之后,我们再次启动felix并输入命令:
____________________________
Welcome to Apache Felix Gogo
g! install file:plugins/osgihello_1.0.0.201807241922.jar
Bundle ID: 8
g! start 8
Hello World!!
g! stop 8
Goodbye World!!
g! uninstall 8
g! start 8
Bundle ID 8 is invalid.
g!
可以看到,我们可以通过start和stop对插件进行热操作,并通过install和uninstall对插件进行热插拔。
4字节码生成技术与动态代理的实现
javac命令使用了字节码生成技术。
web服务器中的jsp编译器,编译时植入的aop框架,还有常用的动态代理技术,甚至在使用反射的时候虚拟机都有可能会在运行时生成字节码来提高执行速度。
动态代理中所谓的动态,是针对使用java代码实际编写了代理类的静态代理而言的。它的又是不在于省去了编写代理类的工作量,而是实现了可以在原始类和接口还未知的时候,就确定代理类的行为。
示例2--对比代理方式的差异
我们定义一个简单的计算器接口,然后定义其实现类,通过静态代理、动态代理(javac、cglib)实现实体类的生成:
接口:
package instance;
public interface Calculator {
int add(int a,int b );
}
实现类:
package instance;
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
方式1——静态代理
public class CalculatorProxy implements Calculator {
private CalculatorImpl calculator;
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
init();
return calculator.add(a, b);
}
public CalculatorImpl getCalculator() {
return calculator;
}
public void init(){
if(calculator==null){
calculator = new CalculatorImpl();
}
}
}
测试:
public static void main(String[] args) {
CalculatorProxy proxy = new CalculatorProxy();
System.out.println(proxy.getCalculator());
System.out.println(proxy.add(1, 2));
System.out.println(proxy.getCalculator());
}
console:
null
3
instance.CalculatorImpl@15db9742
方式2——实现invocationHandler的动态代理:
package dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CalHandler implements InvocationHandler {
Object obj;
public CalHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub4
Object o = null;
this.doBefore(o);
o = method.invoke(obj, args);
this.doAfter(o);
return o;
}
public void doBefore(Object o){
System.out.println(o);
}
public void doAfter(Object o){
System.out.println(o);
}
}
测试:
public static void main(String[] args) {
Calculator calculator = new CalculatorImpl();
CalHandler lh = new CalHandler(calculator);
Calculator proxy = (Calculator) Proxy.newProxyInstance(calculator
.getClass().getClassLoader(), calculator.getClass()
.getInterfaces(), lh);
System.out.println(proxy.add(1, 1));
}
console:
null
2
2
方式3——使用cglib实现动态代理
package cglibProxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CalculatorCglib implements MethodInterceptor {
private Object target;
public Object getInstace(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
Object object = null;
doBefore(object);
object = proxy.invokeSuper(obj, args);
doAfter(object);
return object;
}
public void doBefore(Object o){
System.out.println(o);
}
public void doAfter(Object o){
System.out.println(o);
}
}
测试:
public static void main(String[] args) {
CalculatorImpl cal = new CalculatorImpl();
CalculatorCglib cglib = new CalculatorCglib();
Calculator cals = (Calculator) cglib.getInstace(cal);
System.out.println(cals.add(1, 2));
}
console:
null
3
3
Retrotranslator:跨越jdk版本
java逆向移植工具
jdk升级新增的功能分为4类:
编译器层的改进、对javaapi的代码增强、需要在字节码中进行支持的改动、虚拟机内部的改进