Java中的动态代理

JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程。下面我们看一个示例:
/**
定义一个Animal接口
**/
public interface Animal {
void eat();
}

/**
定义一个Animal接口的实现类Cat
**/
public class Cat implements Animal {
public void eat() {
System.out.println(“Cat eat”);
}
}

/**
定义一个InvocationHandler接口的实现类AnimalInvocationHandler
**/
public class AnimalInvocationHandler implements InvocationHandler {

private Object mProxy;

public AnimalInvocationHandler(Object object){
    mProxy = object;
}

/**
 * 通过Proxy.newProxyInstance方法生产动态代理类
 * @return
 */
public Object getProxy(){
    return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), mProxy.getClass().getInterfaces(), this);
}

/**
 * 掉用被代理类的接口方法最终会掉用invoke方法
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
   System.out.println("----- before -----");
   Object result = method.invoke(mProxy, args);
   System.out.println("----- after -----");
   return result;
}

}

/**
测试类
**/
public class Main {

public static void main(String[] args) throws Exception{
    Animal animal = new Cat();
    AnimalInvocationHandler animalInvocationHandler = new AnimalInvocationHandler(animal);
    Animal proxy = (Animal)animalInvocationHandler.getProxy();
    proxy.eat();
    createProxyClassFile();

}

/**
 * 将动态生产的代理类class文件保存下来
 */
 public static void createProxyClassFile()   
  {   
    String name = "ProxySubject";   
    byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Animal.class } );   
    try  
    {   
      FileOutputStream out = new FileOutputStream( name + ".class" );   
      out.write( data );   
      out.close();   
    }   
    catch( Exception e )   
    {   
      e.printStackTrace();   
    }   
  }   

}
运行main方法我们可以看到当掉用Animal proxy = (Animal)animalInvocationHandler.getProxy();
proxy.eat();
最终掉用的是AnimalInvocationHandler类中的invoke方法。
WHY?我们可以看下保存下来的动态生成类的class 代码:
public final class ProxySubject extends Proxy implements Animal
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;

public ProxySubject(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}

public final boolean equals(Object paramObject)
{
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 eat()
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

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

public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
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.zld.dynamicproxy.Animal”).getMethod(“eat”, new Class[0]);
m2 = Class.forName(“java.lang.Object”).getMethod(“toString”, new Class[0]);
m0 = Class.forName(“java.lang.Object”).getMethod(“hashCode”, new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

可以看到该类继承自Proxy并实现了Animal接口,在看下该类的eat方法就明白了为什么会掉用AnimalInvocationHandler类的invoke方法。
PS(ProxyGenerator类的导入可以通过点击右边的Add》打开access rules设置》选择resolution为accessible》按照提示在下面的rule pattern输入相应的pattern;

pattern 可以输入* 代表所有的包均可导入 ,也可以输入相应包路径下面的类可以进入访问,例如sun/misc/*等等;)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值