前些天一个朋友去参加摸互联网公司的面试,面试官问了他关于动态代理的一些问题,结果他就完全晕菜了,后来让我给他讲讲动态代理的知识。现在我就吧个人对动态代理的了解跟大家跟大家分享一下,欢迎大家批评指正。
我个人认为学习Java最好的工具就是JDK文档,今天我们就从jdk文档中对动态代理的介绍开始,和大家一起学习动态代理相关的知识。
谈到动态代理,搜西安要认识的就是java.lang.reflect.Proxy类,JDK文档中对这个类的介绍如下所示:
java.lang.reflect
Class Proxy
- java.lang.Object
-
- java.lang.reflect.Proxy
-
-
All Implemented Interfaces:
- Serializable
public class Proxy extends Object implements Serializable
Proxy
provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.To create a proxy for some interface
Foo
:InvocationHandler handler = new MyInvocationHandler(...); Class proxyClass = Proxy.getProxyClass( Foo.class.getClassLoader(), new Class[] { Foo.class }); Foo f = (Foo) proxyClass. getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
or more simply:Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler
上面的介绍大概就是说Proxy提供了一些可以创建动态代理类和代理对象的静态方法(例如newProxyInstance),所有由它的静态方法产生的动态代理类都是它的子类。后面又非常详细地通过例子介绍了创建动态代理对象的两种方法。第一种方法看起来相对以后面一种稍微麻烦,大概意思就是,先通过getProxyClass方法获取代理类,然后就是使用代理类来构造代理对象,Proxy没有Public权限构造方法,
仅有一个Protected权限的构造方法,所以这里使用了反射,先获取构造方法,再通过构造方法来创建对象。
相对于第一种方法,第二种方法看起来十分简单,就是使用了Proxy类提供的一个静态方法,直接获取到了代理对象。、
两种方法都用到了一个接口,就是InvocationHandler,而且它还是Prox构造方法的唯一参数,可见这个Invocation非常重要,下面我们再看看JDK文档是怎么介绍IncocationHandler的。
java.lang.reflect
Interface InvocationHandler
-
-
All Known Implementing Classes:
- CompositeDataInvocationHandler, EventHandler, MBeanServerInvocationHandler, RemoteObjectInvocationHandler
public interface InvocationHandler
InvocationHandler
is the interface implemented by the invocation handler of a proxy instance.Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the
invoke
method of its invocation handler.-
Since:
- 1.3 See Also:
-
Proxy
上面JDK文档的大概就是说所有的Proxy真实处理类都要实现这个接口,每一个动态代理实例都持有一个实现该接口的引用,对代理对象的调用都会最终通过个对象里进行处理。所以,实现这个接口是实现动态代理的关键。
现在,动态代理大家应该都差不多明白了,下面我们就开始动手实现一下,首先给出比较简单的方法,就是使用Proxy的newProxyInstance静态方法,具体实现如下:
/**
* <p>通过Proxy的newProxyInstance静态方法实现动态代理</p>
* @author zhangmeng
* zhangmeng
* 2015年8月3日
*
*/
public class Handler1 implements InvocationHandler {
Object target;
public Object bind(Object target){
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces() , this);
}
/* (non-Javadoc)
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
* @author zhangmeng
* @param proxy 被代理的对象
* @param method 要调用的方法
* @param args 方法调用时需要的参数
* @return
* @throws Throwable
* 2015年8月3日
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("代理开始");
method.invoke(target, args);
System.out.println("代理结束");
return null;
}
public static void main(String[] args) {
Handler1 handler=new Handler1();
Animal dog=(Animal)handler.bind(new Dog());
dog.speak();
}
}
/**
* <p>将要被代理的接口</p>
* @author zhangmeng
* 2015年8月3日
*
*/
interface Animal{
public void speak();
}
/**
* <p>接口具体实现</p>
* @author zhangmeng
* 2015年8月3日
*
*/
class Dog implements Animal{
@Override
public void speak() {
System.out.println("wangwang");
}
}
看起来是不是非常简单呢?那下面再看看通过反射来构造动态代理对象的具体例子:
/**
* <p>通过反射实现动态代理</p>
* @author zhangmeng
* zhangmeng
* 2015年8月3日
*
*/
public class Handler2 implements InvocationHandler {
Object target;
public Object bind(Object target) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
this.target=target;
Class proxyClass = Proxy.getProxyClass(this.getClass().getClassLoader(), target.getClass().getInterfaces());
System.out.println(proxyClass);
return proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(this);
}
/* (non-Javadoc)
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
* @author zhangmeng
* @param proxy 被代理的对象
* @param method 要调用的方法
* @param args 方法调用时需要的参数
* @return
* @throws Throwable
* 2015年8月3日
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("代理开始");
method.invoke(target, args);
System.out.println("代理结束");
return null;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Handler2 handler=new Handler2();
Animal dog=(Animal)handler.bind(new Dog());
dog.speak();
}
}
上面两个例子输出的结果都是:
代理开始
wangwang
代理结束
代理结束