原文链接: jdk动态代理

注:文章中用常用的流程实现 动态代理,流程逻辑比较清晰。文章后面对 “为什么要使用接口” 原理分析还未细看。

jdk的动态代理为什么用接口,内部是什么原理呢?看了几篇文章貌似都没讲的清楚明白,因此来解释一下。

先通过一个简单例子实现功能:

 //接口
public interface SayService { void say(String name);
}
//实现类
public class SayServiceImpl implements SayService{ @Override
public 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;
} @Override
public 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());
}
}
}

---------------------
作者:锐锐
来源:CSDN
原文:https://blog.csdn.net/ray890206/article/details/70146029
版权声明:本文为博主原创文章,转载请附上博文链接!

转:jdk动态代理实现的更多相关文章

  1. JDK动态代理

    一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...

  2. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  3. Spring中的JDK动态代理

    Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...

  4. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  5. JDK动态代理的实现原理

    学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504

  6. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

  7. JDK动态代理与CGLib动态代理

    1.JDK动态代理 JDK1.3以后java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,动态代理是实现AOP的绝好底层技术. JDK的动态代理主要涉及到java.lang.reflect ...

  8. jdk动态代理实现

    1.jdk动态代理的简单实现类 package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.refl ...

  9. java jdk动态代理

    在面试的时候面试题里有一道jdk的动态代理是原理,并给一个事例直接写代码出来,现在再整理一下 jdk动态代理主要是想动态在代码中增加一些功能,不影响现有代码,实现动态代理需要做如下几个操作 1.首先必 ...

  10. JDK动态代理的实现及原理

    Proxy.newProxyInstance(classloader,Class,invocationHandler) 调用getProxyClass0(loader, interfaces)生成代理 ...

随机推荐

  1. LeetCode: First Missing Positive 解题报告

    First Missing Positive Given an unsorted integer array, find the first missing positive integer. For ...

  2. 【九天教您南方cass 9.1】 14 坐标数据的纠正

    同学们大家好,欢迎收看由老王测量上班记出品的cass9.1视频课程 我是本节课主讲老师九天. 我们讲课的教程附件也是共享的,请注意索取 在测量空间中. 九天老师的联系方式  点击直接请教九天老师吧! ...

  3. React Native常用组件之ScrollView

    1. 两个要点 1.1 ScrollView必须有一个确定的高度才能正常工作 它实际上所做的就是将一系列不确定高度的子组件装进一个确定高度的容器(通过滚动操作) 通常有两种做法: 第一种: 直接给该S ...

  4. .NET解决[Serializable] Attribute引发的Json序列化k_BackingField

    在WebAPI中的WebApiConfig直接加入如下配置 有问题找谷歌

  5. Nginx-配置https虚拟服务(访问http时自动跳转https)

    https口令文件和nginx配置文件位置关系: nginx配置文件内容如下: #user nobody; worker_processes 1; #设置工作进程数 pid logs/nginx.pi ...

  6. js中的XMLHTTPRequest

    window.onload = function(){ //var url = "http://localhost:8000/sales.json"; var url = &quo ...

  7. WP8.1学习系列(第二十七章)——ListView和GridView入门

    快速入门:添加 ListView 和 GridView 控件 (XAML)   在本文中 先决条件 选择 ListView 或 GridView 将项添加到项集合 设置项目源 指定项目的外观 指定视图 ...

  8. springboot之thymeleaf学习

    这是springboot的view层不建议使用jsp,而是thymeleaf,虽然我也不知道为什么,但是后来可能会明白一些.学springBoot也遇到很多bug,导致脱累了进度.有点类似于jsp,但 ...

  9. day_5.22 py

    #!/usr/bin/env/python #-*-coding:utf-8-*- ''' 私有化 __相当于prevate 外部不能直接调用,只能通过set get方法用 property ''' ...

  10. 源码安装git工具,显示/usr/local/lib64/libcrypto.a(dso_dlfcn.o) undefined reference to `dlopen'

    /usr/local/lib64/libcrypto.a(dso_dlfcn.o): In function `dlfcn_globallookup':dso_dlfcn.c:(.text+0x30) ...