类加载器,动态代理

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. 使用动态代理

(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());
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值