【深入JAVA】JDK静动态代理

来源:互联网 发布:windows 7评价 编辑:程序博客网 时间:2024/05/20 19:45

静态代理:是由程序员创建或特定工具自动生成源代码,再对其进行编译,在程序运行前,代理类的.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 stubSystem.out.println("调用查看账户方法...");}public void updateCount() {// TODO Auto-generated method stubSystem.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





0 0
原创粉丝点击