在学习HadoopRPC时。用到了函数调用。函数调用都是採用的java的反射机制和动态代理来实现的,所以如今回想下java的反射和动态代理的相关知识。
一、反射
JAVA反射机制定义: JAVA反射机制是java程序在执行状态中。对于随意一个类,都能够知道这个类的所有属性和方法;对于随意一个对象,都能够调用它的随意一个方法;这样的动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射就是把Java类中的各种成分映射成对应的Java类。
Java反射机制主要提供了下面功能:
1、在执行时推断随意一个对象所属的类。
2、在执行时构造随意一个类的对象;
3、在执行时推断随意一个类所具有的成员变量和方法;
4、在执行时调用随意一个对象的方法;
5、生成动态代理。
我们了解了反射机制的功能,那么我们怎样详细来实现它呢?
一个类中的每一个成员都能够用对应的反射包中的一个类的实例对象来表示,通过Class类的方法能够得到这些实例对象。这个“成员”就包括:类的构造函数、成员变量、方法等一些信息。而他们所对应的反射包中的类各自是:Constructor类、Field类、Method类。
这里仅仅要讲讲动态代理的知识。
二、动态代理
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到下面两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时。第一个參数obj通常是指代理类。method是被代理的方法,如上例中的request()。args为该方法的參数数组。
这个抽象方法在代理类中动态实现。
(2).Proxy:该类即为动态代理类。作用相似于上例中的ProxySubject,当中主要包括下面内容:
Protected Proxy(InvocationHandler h):构造函数。预计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类。当中loader是类装载器,interfaces是真实类所拥有的所有接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类能够当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
实例:
1、定义一个HelloWorld接口
/**
* 定义一个HelloWorld接口
*
* @author
*
*/
public interface HelloWorld {
public void sayHelloWorld();
}
2、类HelloWorldImpl是HelloWorld接口的实现
/**
* 类HelloWorldImpl是HelloWorld接口的实现
*
* @author
*
*/
public class HelloWorldImpl implements HelloWorld{
public void sayHelloWorld() {
System.out.println("HelloWorld!");
}
}
3、HelloWorldHandler是 InvocationHandler接口实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 实如今方法调用前后向控制台输出两句字符串
*
* @author
*
*/
public class HelloWorldHandler implements InvocationHandler{
//要代理的原始对象
private Object obj;
public HelloWorldHandler(Object obj) {
super();
this.obj = obj;
}
/**
* 在代理实例上处理方法调用并返回结果
*
* @param proxy 代理类
* @param method 被代理的方法
* @param args 该方法的參数数组
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
//调用之前
doBefore();
//调用原始对象的方法
result=method.invoke(obj, args);
//调用之后
doAfter();
return result;
}
private void doBefore(){
System.out.println("before method invoke");
}
private void doAfter(){
System.out.println("after method invoke");
}
}
4、測试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class HelloWorldTest {
public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorldImpl();
InvocationHandler handler=new HelloWorldHandler(helloWorld);
//创建动态代理对象
HelloWorld proxy=(HelloWorld)Proxy.newProxyInstance(
helloWorld.getClass().getClassLoader(),
helloWorld.getClass().getInterfaces(),
handler);
proxy.sayHelloWorld();
}
}
执行结果为:
before method invoke
HelloWorld
after method invoke
总结:
一个典型的动态代理创建对象过程可分为下面四个步骤:
1、通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通过反射机制获取动态代理类的构造函数,其參数类型是调用处理器接口类型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通过构造函数创建代理类实例。此时需将调用处理器对象作为參数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
为了简化对象创建过程。Proxy类中的newInstance方法封装了2~4。仅仅需两步就可以完毕代理对象的创建。
生成的ProxySubject继承Proxy类实现Subject接口。实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
综合上面所说的,作为一个Dynamic Proxy,它必须满足下面三个条件:
1、实现了InvocationHandler接口,实现接口中定义的invoke方法。
2、包括接口实现类的实例;
3、通过Proxy.newProxyInstance方法实现Proxy与接口之间的绑定
再来回想一下定义
Dynamic Proxy是这样一种class:它是在执行时生成的class,在生成它时你必须提供一组interface给它。然后该class就宣称它实现了这些 interface。你当然能够把该class的实例当作这些interface中的不论什么一个来用。
当然啦,这个Dynamic Proxy事实上就是一个Proxy。它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作 。