【深入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
- 【深入JAVA】JDK静动态代理
- 深入理解JAVA JDK动态代理机制
- 深入理解JAVA JDK动态代理机制
- 深入理解JDK动态代理
- 动态代理--java jdk
- java jdk动态代理
- Java JDK动态代理
- java jdk 动态代理
- Java JDK 动态代理
- java jdk动态代理
- Java JDK 动态代理
- Java-JDK动态代理
- java jdk动态代理
- Java动态代理--jdk代理
- java动态代理 JDK、Cglib动态代理
- Java中的动态代理--JDK动态代理
- Java动态代理之JDK动态代理
- 深入理解JDK动态代理机制
- LINUX服务器之间用Rsync同步数据
- 设计模式之 - 访问者模式
- 深入浅出UML类图
- Android butterknife框架
- UIView与CALayer的区别,很详细
- 【深入JAVA】JDK静动态代理
- Android Studio开发入门-引用jar及so文件
- 2015年第十四周oj刷题:输出日期时间--友元类
- 如何理解RESTful架构
- g++和gcc的相同点和区别
- Object-C kvc
- WebView
- ubuntu安装vmwareTools方法
- Android-Universal-Image-Loader最新框架解析