JDK动态代理浅析

前些天一个朋友去参加摸互联网公司的面试,面试官问了他关于动态代理的一些问题,结果他就完全晕菜了,后来让我给他讲讲动态代理的知识。现在我就吧个人对动态代理的了解跟大家跟大家分享一下,欢迎大家批评指正。

        我个人认为学习Java最好的工具就是JDK文档,今天我们就从jdk文档中对动态代理的介绍开始,和大家一起学习动态代理相关的知识。

        谈到动态代理,搜西安要认识的就是java.lang.reflect.Proxy类,JDK文档中对这个类的介绍如下所示:

java.lang.reflect

Class 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

    • Method Summary

      Methods  
      Modifier and Type Method and Description
      Object invoke(Object proxy, Method method, Object[] args)
      Processes a method invocation on a proxy instance and returns the result.

上面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
代理结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值