代理模式&java动态代理

       所谓代理模式是指:为其他对象提供一种代理以控制对这个对象的访问。可以简单的理解为,一个类要做某个事,这个类可以把做这个事的权限交予其他类,其他类就成为了这个类的代理者。比如总经理可以安排自己的日程,也可以把这个任务委托给秘书来做,那么这么做的意义是什么呢?就是秘书做这件事的时候可以做一些总经理不会做的准备性的工作。

       

      第一个例子是一个简单的代理模式的实现:

      Interface:

package com.gc.impl;

public interface TimeBookInterface{
	public void doAuditing(String name);
}
       Implements:
package com.gc.action;

import com.gc.impl.TimeBookInterface;

public class TimeBook implements TimeBookInterface{	
	public void doAuditing(String name){
		System.out.println("audit now...");
	}
}
      Proxy:
package com.gc.action;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.gc.impl.TimeBookInterface;

public class TimeBookProxy{
	private Logger logger = Logger.getLogger(this.getClass().getName());
	private TimeBookInterface timeBookInterface;
	public TimeBookProxy(TimeBookInterface timeBookInterface){
		this.timeBookInterface = timeBookInterface;
	}
	public void doAuditing(String name){
		logger.log(Level.INFO, name+"开始审核数据");
        this.timeBookInterface.doAuditing(name);
		logger.log(Level.INFO, name+"结束审核数据");
	}
}

       Test类:

package com.gc.test;

import com.gc.action.*;

public class TestHelloWorld{
	public static void main(String[] args) {
		TimeBookProxy timeBookProxy = new TimeBookProxy(new TimeBook());
		timeBookProxy.doAuditing("张三");
	}
}

       通过将实现类传入ProxyClass,代理类达到了代理的目的。我们看到代理类调用了指定的方法,并且在调用方法的前后增加了必要的打log逻辑。 

       这种代理模式不局限于java,同样可以用其他面向对象语言实现。

       

       java同样提供了一种动态代理方式,这种方式基于java的反射的特性,下面提供一个动态代理的例子。接口和类是上例中的类。

       LogProxy类:

package com.gc.action;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class logProxy implements InvocationHandler{
    
	private Object delegate;
	
	public Object bind(Object delegate){
		this.delegate = delegate;
		return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("before");
		Object result = method.invoke(delegate, args);
		System.out.println("after");
		return result;
	}
	
}

      Test类:

package com.gc.test;

import com.gc.action.*;
import com.gc.impl.*;

public class TestHelloWorld{
	public static void main(String[] args){
		logProxy logProxy1 = new logProxy();
		TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy1.bind(new TimeBook());
		timeBookProxy.DoAuditing("张三");
	}
}
       下面分析一下整个代理的过程:

TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy1.bind(new TimeBook());
public Object bind(Object delegate){
		this.delegate = delegate;
		return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
	}
	
       ProxyClass的bind操作接受一个实现类作为自己的参数,并返回一个代理类,程序将代理类强制转化为TimeBookInterface类型,然后调用TimeBookInterface的相应方法。        先看下运行结果:

       

       最后调用

timeBookProxy.DoAuditing("张三");
       方法之后,程序不仅调用了实现类中的doAuditing方法,而且执行了代理类中的两次打印操作,说明最后执行了Proxy类的invoke方法。

       那么为什么通过TimeBookInterface调用doAuditing方法可以会调用invoke方法呢?笔者在刚接触这个特性的时候有两个想法:

       1、Proxy.newProxyInstance方法调用返回的肯定是一个代理类,并且实现了TimeBookInterface的接口。否则不能强制转化为TimeBookInterface类型。

       2、这个代理类还要继承自logProxy类,否则它不能调用invoke方法。

       事实这个类是什么样子呢?我们在main方法最前面加上,将生成的ProxyClass打印出来

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
		
       通过JavaDecompiler这个工具得到这个类:

import com.gc.impl.TimeBookInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy
  implements TimeBookInterface
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;

  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void DoAuditing(String paramString)
    throws 
  {
    try
    {
      this.h.invoke(this, m3, new Object[] { paramString });
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
    throws 
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.gc.impl.TimeBookInterface").getMethod("DoAuditing", new Class[] { Class.forName("java.lang.String") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

        可以看到,当调用这个类的doAuditing方法的时候调用的是 this.h.invoke(this, m3, new Object[] { paramString }) 

        这个类本身继承自Proxy类,查看Proxy源码可知h是invocationHandler,也就是说这个类通过调用传入的invocationHandler的invoke方法而实现代理类中相应方法的调用。在这个例子中,由于logProxy方法实现了invocationHandler,并且把这个参数传给了生成的代理类,这个代理类调用doAuditing方法也就是调用了logProxy方法中的invoke方法,从而达到的代理的效果。

       也就是说,第二个猜想是错误的。生成的代理类并没有继承logProxy而是继承自Proxy类,而Proxy类中包含invocationHandler属性,在newProxyInstance的时候,invocationHandler已经传入要生成的代理类,通过调用这个invocationHandler的invoke方法,达到调用logProxy中的invoke方法的目的。 

       

      

       

       

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值