转:jdk动态代理实现
原文链接: 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动态代理实现的更多相关文章
- JDK动态代理
一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...
- 静态代理和利用反射形成的动态代理(JDK动态代理)
代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...
- Spring中的JDK动态代理
Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...
- AOP学习心得&jdk动态代理与cglib比较
什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...
- JDK动态代理的实现原理
学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504
- Java中的JDK动态代理
所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...
- JDK动态代理与CGLib动态代理
1.JDK动态代理 JDK1.3以后java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,动态代理是实现AOP的绝好底层技术. JDK的动态代理主要涉及到java.lang.reflect ...
- jdk动态代理实现
1.jdk动态代理的简单实现类 package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.refl ...
- java jdk动态代理
在面试的时候面试题里有一道jdk的动态代理是原理,并给一个事例直接写代码出来,现在再整理一下 jdk动态代理主要是想动态在代码中增加一些功能,不影响现有代码,实现动态代理需要做如下几个操作 1.首先必 ...
- JDK动态代理的实现及原理
Proxy.newProxyInstance(classloader,Class,invocationHandler) 调用getProxyClass0(loader, interfaces)生成代理 ...
随机推荐
- sklearn linear_model,svm,tree,naive bayes,ensemble
sklearn linear_model,svm,tree,naive bayes,ensemble by iris dataset .caret, .dropup > .btn > .c ...
- 假期小结 BIO, NIO, AIO
虽然忙碌,但仍小有收获,开心. 引子 BIO: Blocking IO,阻塞式IO NIO: Non-blocking IO,非阻塞式IO AIO: Async IO,异步IO 问题 什么是阻塞式IO ...
- 查看CPU/CACHE的拓扑结构
转自 http://smilejay.com/2017/12/cpu-cache-topology/ Linux上,CPU和Cache相关的拓扑结构,都可以从sysfs文件系统的目录 /sys/dev ...
- pixmap和label设置图片自适应大小
在label中添加pixmap来显示图片时,当图片过大时图片显示不全. 1.这时可以使用pixmap的scared()方法,来设置图片缩放. QPixmap QPixmap.scaled (self, ...
- Python实现C代码统计工具(二)
目录 Python实现C代码统计工具(二) 声明 一. 问题提出 二. 代码实现 三. 效果验证 Python实现C代码统计工具(二) 标签: Python 代码统计 声明 本文将对<Pytho ...
- 关于H5页面在iPhoneX适配(转)
1. iPhoneX的介绍 屏幕尺寸 我们熟知的iPhone系列开发尺寸概要如下: △ iPhone各机型的开发尺寸 转化成我们熟知的像素尺寸: △ 每个机型的多维度尺寸 倍图其实就是像素尺寸和开 ...
- [原]jenkins(六)---jenkins远程部署脚本
/** * lihaibo * 文章内容都是根据自己工作情况实践得出. * 版权声明:本博客欢迎转发,但请保留原作者信息! http://www.cnblogs.com/horizonli/p/533 ...
- day_5.19 py总结②
- [转] - Spark排错与优化
Spark排错与优化 http://blog.csdn.net/lsshlsw/article/details/49155087 一. 运维 1. Master挂掉,standby重启也失效 Mast ...
- 火狐浏览器报错“support.mozilla.org
火狐浏览器有时候再打开新网页会报此错“support.mozilla.org 有时候火狐浏览器会出现如下状况 解决方法 在地址栏键入”about:config” 点击“我了解此风险” 在下方任意位置右 ...