JAVA类装载方式,有两种:
1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
2.显式装载, 通过class.forname()等方法,显式加载需要的类
常见的类加载器有三种,每个类加载器负责加载不同位置的类:
1)Bootstrap 根类加载器;
2)ExtClassLoader 扩展类加载器;
3)AppClassLoader 系统/应用类加载器;
BootStrap 加载/lib文件下的jar
ExtClassLoader 加载/lib/ext/文件下的jar
AppClassLoader 加载ClassPath指定的所有jar或目录。
MyClassLoader MyClassLoader2自定义类加载指定目录
BootStrap加载Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,
ExtClassLoader加载Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.ExtClassLoader是用Java写的
AppClassLoader
Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为 ExtClassLoader,它的实现类是 sun.misc.Launcher$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。
获取一个类的类加载器
ClassLoader getClassLoader() 返回该类的类加载器
AppClassLoader:加载classPath中的所有的类,也就是我们自己写的那些类!
public class ClassLoaderDemo1 {
public static void main(String[] args) {
// 获取当前类的加载器
ClassLoader loader = ClassLoaderDemo1.class.getClassLoader();
//输出当前类的类加载器
System.out.println(loader);//sun.misc.Launcher$AppClassLoader@b0014f0
}
}
第2章 动态代理
2.1 代理模式
二:动态代理的第一种实现——JDK动态代理
代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。代理可以帮助我们进行很好的封装,使底层的代码能够有效的隐藏起来。
1:首先,定义业务逻辑接口
public interface BookFacade {
public void addBook();
}
2:然后,实现业务逻辑接口创建业务实现类
public class BookFacadeImpl implements BookFacade {
@Override
public void addBook() {
System.out.println("增加图书方法。。。");
}
}
3:最后,实现 调用管理接口InvocationHandler 创建动态代理类。下面我们来具体介绍下如何使用动态代理方式实现我们的需求。
- 使用动态代理
(1)InvocationHandler接口
在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口,这个接口的定义如下:
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args);
}
因此我们只需在中介类的invoke方法实现中输出“before”,然后调用委托类的invoke方法,再输出“after”。
(2)委托类的定义
动态代理方式下,要求委托类必须实现某个接口,这里我们实现的是Sell接口。委托类Vendor类的定义如下:
public class Vendor implements Sell {
public void sell() {
System.out.println("In sell method");
}
public void ad() {
System,out.println("ad method")
}
}
代理和被代理对象实现的接口:
/*
* 描述明星的接口
*/
public interface Star {
//成员函数 唱歌
public abstract void sing(double money);
//综艺节目
public abstract void liveShow(double money);
//睡觉
public abstract void sleep();
}
被代理类即明星的代码:
/*
* 被代理对象 目标业务对象 明星柳岩
*/
public class LiuYan implements Star{
//唱歌
public void sing(double money) {
System.out.println("唱了一首:甜蜜蜜");
System.out.println("赚了"+money+"元");
}
//参加综艺节目
public void liveShow(double money) {
System.out.println("参加了:奔跑吧,兄弟");
System.out.println("赚了"+money+"元");
}
//睡觉
public void sleep() {
System.out.println("好累啊,休息一会。。。。。");
}
}
代理对象即经纪人的代码如下所示:
/*
* 代理对象 锁哥 经纪人
*/
public class SuoGe implements Star {
// 持有被代理对象
private LiuYan ly = new LiuYan();
public void sing(double money) {
// 对money变量进行判断,修改访问参数
if (money < 100000) {
System.out.println("滚,穷屌丝,一边玩泥巴去");
return;
}
System.out.println("我抽取了" + money * 0.2 + "元代理费用");
ly.sing(money * 0.8);
}
public void liveShow(double money) {
// 对money变量进行判断,修改访问参数
if (money < 500000) {
System.out.println("滚,穷屌丝,一边玩泥巴去");
return;
}
System.out.println("我抽取了" + money * 0.2 + "元代理费用");
ly.liveShow(money * 0.8);
}
public void sleep() {
ly.sleep();
}
}
测试类中的主函数代码:
/*
* 代理模式演示
*/
public class ProxyDemo1 {
public static void main(String[] args) {
// 创建LiuYan对象
// LiuYan ly = new LiuYan();
// ly.sing(1000);
// ly.liveShow(5000);
// ly.sleep();
//直接访问经纪人
SuoGe sg = new SuoGe();
sg.sing(200000);
System.out.println("-----------------------------------");
sg.liveShow(1000000);
System.out.println("-----------------------------------");
sg.sleep();
}
}
2.2 动态代理(很难)
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例或者对象。
1) loader:类加载器。一个类的字节码文件不可能直接就出现在方法区中,必须通过一个类的类加载器将类的字节码文件加载到方法区中,
所以需要一个类加载器。
那么我们如何确定这个类加载器呢?
public class CalculatorHandler implements InvocationHandler {
private Object obj; //被代理类
public CalculatorHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("in calculatorhandler, before invocation");
Object ret = method.invoke(obj, args); //执行被代理类方法
System.out.println("in calculationhandler, after invocation");
return ret;
}
}
Calculator calculator = (Calculator) Proxy.newProxyInstance(calculatorImpl.getClass().getClassLoader(), calculatorImpl.getClass().getInterfaces(), calculatorHandler);
// InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发
// 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..);
// 通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });
// 通过反射从生成的类对象获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
// 通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
动态代理代码详解:
public class CalculatorHandler implements InvocationHandler {
private Object obj; //被代理类
public CalculatorHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("in calculatorhandler, before invocation");
Object ret = method.invoke(obj, args); //执行被代理类方法
System.out.println("in calculationhandler, after invocation");
return ret;
}
}
生成动态代理
CalculatorImpl calculatorImpl = new CalculatorImpl();//被代理类
CalculatorHandler calculatorHandler = new CalculatorHandler(calculatorImpl);
Calculator calculator = (Calculator) Proxy.newProxyInstance(calculatorImpl.getClass().getClassLoader(), calculatorImpl.getClass().getInterfaces(), calculatorHandler);
System.out.println(calculator.add(1,2));
System.out.println(calculator.minus(1, 2));
无论calculator中包含多少函数,动态代理只需实现一次,实际工程中,System.out.println(“in calculatorhandler, before invocation”)可能是加缓存,打日志等操作
动态代理如何工作的
为了搞清楚动态代理如何工作,首先看看生成的动态代理的代码是什么,借助[1]中ProxyUtil代码
public class ProxyUtils {
/**
* Save proxy class to path
*
* @param path path to save proxy class
* @param proxyClassName name of proxy class
* @param interfaces interfaces of proxy class
* @return
*/
public static boolean saveProxyClass(String path, String proxyClassName, Class[] interfaces) {
if (proxyClassName == null || path == null) {
return false;
}
// get byte of proxy class
byte[] classFile = ProxyGenerator.generateProxyClass(proxyClassName, interfaces);
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
}
得到了生成的动态代理代码如下:
public final class $Proxy0 extends Proxy
implements Calculator
{
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final Integer minus(Integer integer, Integer integer1)
{
try
{
return (Integer)super.h.invoke(this, m4, new Object[] {
integer, integer1
});
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final Integer add(Integer integer, Integer integer1)
{
try
{
return (Integer)super.h.invoke(this, m3, new Object[] {
integer, integer1
});
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m2;
private static Method m4;
private static Method m3;
private static Method m0;
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.langrx.mq.Calculator").getMethod("minus", new Class[] {
Class.forName("java.lang.Integer"), Class.forName("java.lang.Integer")
});
m3 = Class.forName("com.langrx.mq.Calculator").getMethod("add", new Class[] {
Class.forName("java.lang.Integer"), Class.forName("java.lang.Integer")
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}