为了分析HDFS,就要研究他的RPC机制,为了研究RPC机制,就要了解动态代理,反射机制和NIO,写篇文章就记录下学习动态代理的过程吧。
每一种技术的诞生都是为了解决一个问题,那么我们可以从这么几个问题来了解动态代理。
1.为什么要用动态代理?
2.有动态代理那么有静态代理吗?
3.什么是动态代理?
4.动态代理就java来说怎么代码实现?
好的我们开始解决这些问题,首先是为什么要动态代理,解决这个问题的时候我们可能还要问为什么要用代理,大家可能都听说过java设计模式中的代理模式,那么首先为什么要代理呢?就像一个歌星需要经纪人一样,明星所要做的核心事情就是把歌唱好,但是一个明星除了把歌唱好还要有很多事情要做,比如每天的行程安排,每天化妆等等,这些如果都让歌星做那就太为难歌星了。把这个实例抽象到代码中,就是一个主要的类实现一个核心功能,但是还有很多小的功能要是还在这个主要的类中实现的话,那代码就太复杂了,所以就出现了代理模式,什么叫代理模式呢,就是一个类再配一个代理类,代理类负责实现一些其他的功能像权限,事务等等。这就是静态代理。那么什么事动态代理呢?还是用我们歌星的例子,给歌星化妆这件事把她看成是一个代理,那么静态代理的话有N个歌星就要有N个化妆师,哪去找那么多?完全可以一个化妆师给好几个歌星来化妆。当有一个歌星需要化妆的时候这个化妆师就去代理。抽象都代码中就只要一个动态代理类,就可以为多个原始类进行代理。这其中演变深深包含了面向“类”编程到面向“对象实例object instance”编程的转变。
好的上面我们已经解决了前三个问题,那就直接进入最后一个问题,就是怎么用的问题。从上面的例子我们知道肯定要有N个原始类和代理类。首先我们把实际代理问题抽象成代码实现的时候就要先明确一个问题,所谓代理,就是需要代理类和被代理类有相同的对外接口或者说成服务,所以代理类一般都必须实现了所有被代理类已实现的接口。为了能让动态代理类能够在运行时才去实现原始类已实现的一系列接口并执行接口中相关的方法操作,需要让动态代理类实现JDK自带的java.lang.reflect.InvocationHandler接口,该接口中的invoke()方法能够让动态代理实例在运行时调用被代理类的“对外服务”,即调用被代理类需要对外实现的所有接口中的方法,也就是完成对真实方法的调用。好了直接上代码:
package haoxiang.learningdemo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理的实例
*
* @author haoxiang
*
*/
// 定义一个接口
interface UserMethod {
public void usermethod();
}
// 原始类实现接口并且实现接口中的方法
class RealClassA implements UserMethod {
@Override
public void usermethod() {
System.out.println("This is:ClassA");
}
}
// 动态代理类,需要集成InvocationHandler接口
class Handler implements InvocationHandler {
private UserMethod um;
public Handler(UserMethod um) {
this.um = um;
}
// 重写其中的invoke方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("start----->" + method.getName());
method.invoke(um, args);
return null;
}
}
// 测试类
public class ProxyDemo {
public static void main(String[] args) {
// 实例化动态代理类对象并且传入需要代理的原始类
Handler handler = new Handler(new RealClassA());
//获得被代理类的类加载器,使得JVM能够加载并找到被代理类的内部结构,以及已实现的interface
ClassLoader loader = handler.getClass().getClassLoader();
//获得被代理类已实现的所有接口interface,使得动态代理类的实例
Class<?>[] interfaces = handler.getClass().getInterfaces();
//获得代理的实例
UserMethod um = (UserMethod) Proxy.newProxyInstance(loader, interfaces,handler);
//利用代理实例调用方法
um.usermethod();
}
}
这里可能会有人有疑问,就是代理怎么获得原始类的方法的呢,这就要归功于JAVA的反射机制了,下一篇我会继续分析反射机制。