静态代理:是由程序员创建或特定工具自动生成源代码,再对其进行编译,在程序运行前,代理类的.class文件就已经存在

动态代理:在程序运行时,代理类的.class文件是运用反射机制动态创建而成


一、静态代理

1> 定义一个接口Count


/**
 * 自定义接口
 * @author xwu
 *
 */
public interface Count {
	//查看账户
	public void queryCount();
	//更新账户
	public void updateCount();
}


2>编写实现类

package com.wuxiao.proxy.staticProxy;

/**
 * 接口实现类
 *
 * @author xwu
 *
 */
public class CountImpl implements Count {

	public void queryCount() {
		// TODO Auto-generated method stub
		System.out.println("调用查看账户方法...");
	}

	public void updateCount() {
		// TODO Auto-generated method stub
		System.out.println("调用更新账户方法...");
	}

}


3>编写Count的代理类


package com.wuxiao.proxy.staticProxy;

/**
 * Count的代理类CountProxy
 *
 * @author xwu
 *
 */
public class CountProxy implements Count {

	private CountImpl countImpl;

	public CountProxy(CountImpl countImpl) {
		this.countImpl = countImpl;
	}

	public void queryCount() {
		System.out.println("方法调用之前...");
		countImpl.queryCount();// 调用委托方法
		System.out.println("方法调用之后...");
	}

	public void updateCount() {
		System.out.println("方法调用之前...");
		countImpl.updateCount();// 调用委托方法
		System.out.println("方法调用之后...");
	}

}

4>编写测试类


package com.wuxiao.proxy.staticProxy;

/**
 * 静态代理测试类
 *
 * @author xwu
 *
 */
public class StaticProxyTest {

	public static void main(String[] args) {
		CountImpl countImpl = new CountImpl();
		CountProxy proxy = new CountProxy(countImpl);
		proxy.queryCount();
		proxy.updateCount();
	}

}

5>看一下运行效果


方法调用之前...
调用查看账户方法...
方法调用之后...
方法调用之前...
调用更新账户方法...
方法调用之后...



总结:一个代理类只能为一个接口服务,如果需要代理的接口很多,那么开发过程中将编写大量的代理类,而且所有的代理操作除了调用的方法不一样,其他的操作都一样,这样就造成了大量的重复工作,不会偷懒的程序猿不是好的攻城狮,因此我们可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理了。

二、JDK动态代理

1>自定义一个接口(同上)

2>编写实现类(同上)

3>编写JDK核心代理类


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

/**
 * 切面
 *
 * @author xwu
 *
 */
public class JDKProxyFactory implements InvocationHandler {

	private Object proxyObject; // 目标对象

	public Object createProxyInstance(Object proxyObject) {
		this.proxyObject = proxyObject;

		// 生成代理类的字节码加载器
		ClassLoader classLoader = proxyObject.getClass().getClassLoader();
		// 需要代理的接口,被代理实现的多个接口都必须定义在这里(这是一个缺陷,cglib弥补了这一缺陷)
		Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();
		// 织入器,织入代码并生成代理类
		return Proxy.newProxyInstance(classLoader, proxyInterface, this);
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		PersonServiceBean bean = (PersonServiceBean) this.proxyObject;
		Object result = null;
		// 控制哪些用户切入逻辑,这里是做了用户名过滤,当然你也可以做其他事情
		if (bean.getUser() != null) {
			// 执行原有逻辑
			result = method.invoke(this.proxyObject, args);
		}
		return result;
	}

}

4>编写测试类


package com.wuxiao.proxy;

/**
 * 通过main方法,并设置sun.misc.ProxyGenerator.saveGeneratedFiles参数可以查看生成的proxy文件
 *
 * @author xwu
 *
 */
public class JDKProxyTest {

	public static void main(String[] args) {
		// 设置此系统属性,以查看代理类文件
		System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

		JDKProxyFactory factory = new JDKProxyFactory();
		PersonService bean = (PersonService) factory.createProxyInstance(new PersonServiceBean("lucy"));
		bean.save("abc");// 用户lucy有权限

		PersonService bean2 = (PersonService) factory.createProxyInstance(new PersonServiceBean());
		bean2.save("abc");// 用户为null没有权限
	}

}

5>看看运行效果


这是save方法

总结:JDK动态代理依靠接口实现,没有实现接口的类则不能使用JDK动态代理,这也是JDK动态代理的一个缺陷吧,不过在cglib中得到了弥补.


这个时候我们可以看看程序运行过程中生成的代理类,run上面的main方法之后可以在当前工程根目录中发现一个$Proxy0.class文件,使用反编译工具打开后可以看到具体内容,下面是我测试代码生成的的.class

import com.wuxiao.proxy.PersonService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//代理继承了Proxy类,并实现了Proxy.newProxyInstance中传入的接口
public final class $Proxy0 extends Proxy
  implements PersonService
{
//这些方法在下面的static体中进行了初始化
  private static Method m5;
  private static Method m3;
  private static Method m1;
  private static Method m0;
  private static Method m4;
  private static Method m2;
//构造函数,接收一个InvocationHandler作为参数,这就是为什么Proxy.newProxyInstance方法里
//可以通过InvocationHandler实例作为参数来反射获取Constructer实例
  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws
  {
    super(paramInvocationHandler);
  }
//同下面的save方法
  public final void update(Integer paramInteger, String paramString)
    throws
  {
    try
    {
      this.h.invoke(this, m5, new Object[] { paramInteger, paramString });
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }
//下面通过这个save方法来看看代理对象中的方法是如何调用的
  public final void save(String paramString)
    throws
  {
    try
    {
//全部是通过调用InvocationHandler的invoke方法,传入对应的方法和参数
      this.h.invoke(this, m3, new Object[] { paramString });
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }
  public final boolean equals(Object paramObject)
    throws
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }
  public final int hashCode()
    throws
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }
  public final String getPersonName(Integer paramInteger)
    throws
  {
    try
    {
      return (String)this.h.invoke(this, m4, new Object[] { paramInteger });
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }
  public final String toString()
    throws
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    }
    throw new UndeclaredThrowableException(localThrowable);
  }
  static
  {
    try
    {
      m5 = Class.forName("com.wuxiao.proxy.PersonService").getMethod("update", new Class[] { Class.forName("java.lang.Integer"), Class.forName("java.lang.String") });
      m3 = Class.forName("com.wuxiao.proxy.PersonService").getMethod("save", new Class[] { Class.forName("java.lang.String") });
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m4 = Class.forName("com.wuxiao.proxy.PersonService").getMethod("getPersonName", new Class[] { Class.forName("java.lang.Integer") });
      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());
  }
}




需要解释的地方已经注释在代码中,应该还算清晰明了,后续会贴上cglib的代理还有Spring AOP动态代理的应用


------------------------------

end   by   wuxiao