jdk动态代理为什么要接口
来源:互联网 发布:固定区域放大镜软件 编辑:程序博客网 时间:2024/05/17 05:19
jdk的动态代理为什么用接口,内部是什么原理呢?看了几篇文章貌似都没讲的清楚明白,因此来解释一下。先通过一个简单例子实现功能:
//接口public interface SayService {void say(String name);}//实现类public class SayServiceImpl implements SayService{@Overridepublic void say(String name) {System.out.println(name);}}
然后再自定义一个增强类, 实现InvocationHandler接口:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class WavingInvocationHandler implements InvocationHandler{private Object target;public void setTarget(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法执行之前!");Object obj = method.invoke(target, args);System.out.println("方法执行之后!");return obj;}}
编写测试方法:
import sun.misc.ProxyGenerator;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.lang.reflect.Proxy;public class Test {public static void main(String[] args) {//接口SayService sayService = new SayServiceImpl();//织入类WavingInvocationHandler handler = new WavingInvocationHandler();handler.setTarget(sayService);//代理类--增强的对象SayService s = (SayService) Proxy.newProxyInstance(sayService.getClass().getClassLoader(),sayService.getClass().getInterfaces(), handler);s.say("say()");//执行代理对象完成业务/** 方法执行之前! say() 方法执行之后! *///将jdk中生成代理类输出到本地.Class文件,之后可以通过反编译软件打开查看createProxyClassFile("test12345",sayService.getClass().getInterfaces());}private static void createProxyClassFile(String name,Class<?> [] interfaces){byte[] data = ProxyGenerator.generateProxyClass(name,interfaces);//该方法为jdk中生成代理类的核心方法FileOutputStream out =null;try {out = new FileOutputStream(name+".class");System.out.println((new File(name)).getAbsolutePath());out.write(data);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(null!=out) try {out.close();} catch (IOException e) {e.printStackTrace();}}}}
好奇心强的小伙伴一定看过newProxyInstance方法看过了,里面的getProxyClass方法创建代理类:/* * Look up or generate the designated proxy class. */Class<?> cl = getProxyClass0(loader, intfs);
具体是里面的哪个方法生成的,小伙伴们不用找半天了,慢慢debug后会发现,就是上面提到的
ProxyGenerator.generateProxyClass()
通过该方法生成的代理类如下:通过反编译查看源码,一看便知接口的作用
JDK的动态代理是靠多态和反射来实现的,它生成的代理类需要实现你传入的接口,并通过反射来得到接口的方法对象(下文中的m3),并将此方法对象传参给增强类(上文中的WavingInvocationHandler类)的invoke方法去执行,从而实现了代理功能,故接口是jdk动态代理的核心实现方式,没有它就无法通过反射找到方法,所以这也是必须有接口的原因。不知道大家明白否
public final class test12345 extends Proxy implements SayService { //1、该类实现你传入的接口并实现方法 // 2、通过构造方法传入你定义的增强类对象 // 3、通过反射该接口,得到接口里的Method对象并传参给增强类,然后执行Invoke实现功能 private static Method m1; private static Method m2; private static Method m3; private static Method m0; public test12345(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler);//2.此处的super指向Proxy中的构造方法并赋值(下文的h就是此处的增强类对象), } //略去无关的hashcode和equals方法 public final void say(String paramString) { try { this.h.invoke(this, m3, new Object[]{paramString});//3.此处的h就是InvocationHandler对象,invoke就是你增强类里的方法,传入接口的方法和参数并执行你增强类里的invoke方法,即完成了整个操作! } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static {//1.静态代码块给属性赋值,初始化接口中的方法对象(主要是下面的m3) try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.chenrui.core.jdk.SayService").getMethod("say", new Class[]{Class.forName("java.lang.String")}); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } }}
3 0
- jdk动态代理为什么要接口
- JDK的动态代理为什么要实现所有的接口?
- JDK动态代理为什么必须针对接口
- JDK动态代理为什么必须用接口
- jdk动态代理接口
- jdk的动态代理及为什么需要接口
- JDK的动态代理为什么必须要使用接口与使用CGLIB动态代理
- JDK动态代理源码及源码剖析之为什么只能代理接口
- JDK动态代理(接口的代理)
- JDK动态代理为什么必须用接口以及与CGLIB的对比
- JDK动态代理为什么必须针对接口 其与CGLIB的对比
- 动态代理1 (JDK 需要实现接口)
- java (JDK 接口动态代理)
- 粗略实现jdk中的接口动态代理
- 为什么动态代理只能基于接口?
- spring aop学习6:jdk动态代理(基于接口代理)
- 为什么要使用动态代理?
- Java动态代理(JDK接口代理和Cglib类代理)
- logstash kafka output 日志处理
- 多项式求和 HDU
- Linux下生成patch和打patch
- Handlebars基础
- Linux域名解析配置文件resolv.conf详解
- jdk动态代理为什么要接口
- wxwidgets绘图
- 24点游戏
- 锋利的jQuery总结(三)
- XDOJ-1006-亮亮破解密码(数列中所有区间位操作值之和)
- 免密上传文件到FTP case
- ServiceLoader跟DriverManager使用总结
- 对XML的理解及总结
- Android, 省市县三级联动