java 1.8 动态代理源码分析
JDK8动态代理源码分析
动态代理的基本使用就不详细介绍了:
例子:
- class proxyed implements pro{
- @Override
- public void text() {
- System.err.println("本方法");
- }
- }
- interface pro {
- void text();
- }
- public class JavaProxy implements InvocationHandler {
- private Object source;
- public JavaProxy(Object source) {
- super();
- this.source = source;
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- System.out.println("before");
- Object invoke = method.invoke(source, args);
- System.out.println("after");
- return invoke;
- }
- public Object getProxy(){
- return Proxy.newProxyInstance(getClass().getClassLoader(), source.getClass().getInterfaces(), this);
- }
- public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
- //第一种,自己写
- //1.设置saveGeneratedFiles值为true则生成 class字节码文件方便分析
- System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
- //2.获取动态代理类
- Class proxyClazz = Proxy.getProxyClass(pro.class.getClassLoader(),pro.class);
- //3.获得代理类的构造函数,并传入参数类型InvocationHandler.class
- Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
- //4.通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
- pro iHello = (pro) constructor.newInstance(new JavaProxy(new proxyed()));
- //5.通过代理对象调用目标方法
- iHello.text();
- //第二种,调用JDK提供的方法,实现了2~4步
- Proxy.newProxyInstance(JavaProxy.class.getClassLoader(),proxyed.class.getInterfaces(),new JavaProxy(new proxyed()));
- }
- }
入口:newProxyInstance
- public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
- //Objects.requireNonNull 判空方法,之后所有的单纯的判断null并抛异常,都是此方法
- Objects.requireNonNull(h);
- //clone 类实现的所有接口
- final Class<?>[] intfs = interfaces.clone();
- //获取当前系统安全接口
- final SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- //Reflection.getCallerClass返回调用该方法的方法的调用类;loader:接口的类加载器
- //进行包访问权限、类加载器权限等检查
- checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
- }
- /*
- * Look up or generate the designated proxy class.
- * 查找或生成代理类
- */
- Class<?> cl = getProxyClass0(loader, intfs);
- /*
- * Invoke its constructor with the designated invocation handler.
- * 使用指定的调用处理程序调用它的构造函数
- */
- try {
- if (sm != null) {
- checkNewProxyPermission(Reflection.getCallerClass(), cl);
- }
- //获取构造
- final Constructor<?> cons = cl.getConstructor(constructorParams);
- final InvocationHandler ih = h;
- if (!Modifier.isPublic(cl.getModifiers())) {
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- cons.setAccessible(true);
- return null;
- }
- });
- }
- //返回 代理对象
- return cons.newInstance(new Object[]{h});
- } catch (IllegalAccessException|InstantiationException e) {
- throw new InternalError(e.toString(), e);
- } catch (InvocationTargetException e) {
- Throwable t = e.getCause();
- if (t instanceof RuntimeException) {
- throw (RuntimeException) t;
- } else {
- throw new InternalError(t.toString(), t);
- }
- } catch (NoSuchMethodException e) {
- throw new InternalError(e.toString(), e);
- }
- }
从上面的分析中可以看出,newProxyInstance帮我们执行了生成代理类----获取构造器----生成代理对象这三步;
我们重点分析生成代理类
getProxyClass0
- /**
- * a cache of proxy classes:动态代理类的弱缓存容器
- * KeyFactory:根据接口的数量,映射一个最佳的key生成函数,其中表示接口的类对象被弱引用;也就是key对象被弱引用继承自WeakReference(key0、key1、key2、keyX),保存接口密钥(hash值)
- * ProxyClassFactory:生成动态类的工厂
- * 注意,两个都实现了BiFunction<ClassLoader, Class<?>[], Object>接口
- */
- private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
- /**
- * Generate a proxy class. Must call the checkProxyAccess method
- * to perform permission checks before calling this.
- * 生成代理类,调用前必须进行 checkProxyAccess权限检查,所以newProxyInstance进行了权限检查
- */
- private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
- //实现接口的最大数量<65535;谁写的类能实现这么多接口
- if (interfaces.length > 65535) {
- throw new IllegalArgumentException("interface limit exceeded");
- }
- // If the proxy class defined by the given loader implementing
- // the given interfaces exists, this will simply return the cached copy;
- // otherwise, it will create the proxy class via the ProxyClassFactory
- // 如果缓存中有,就直接返回,否则会生成
- return proxyClassCache.get(loader, interfaces);
- }
proxyClassCache.get
- public V get(K key, P parameter) {
- //key:类加载器;parameter:接口数组
- Objects.requireNonNull(parameter);
- //清除已经被GC回收的弱引用
- expungeStaleEntries();
- //CacheKey弱引用类,refQueue已经被回收的弱引用队列;构建一个CacheKey
- Object cacheKey = CacheKey.valueOf(key, refQueue);
- //map一级缓存,获取valuesMap二级缓存
- ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
- if (valuesMap == null) {
- ConcurrentMap<Object, Supplier<V>> oldValuesMap
- = map.putIfAbsent(cacheKey,
- valuesMap = new ConcurrentHashMap<>());
- if (oldValuesMap != null) {
- valuesMap = oldValuesMap;
- }
- }
- // subKeyFactory类型是KeyFactory,apply返回表示接口的key
- Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
- //Factory 实现了supplier,我们实际是获取缓存中的Factory,调用其get方法
- Supplier<V> supplier = valuesMap.get(subKey);
- Factory factory = null;
- //下面用到了 CAS+重试 实现的多线程安全的 非阻塞算法
- while (true) {
- if (supplier != null) {
- // 只需要知道,最终会调用get方法,此supplier可能是缓存中取出来的,也可能是Factory新new出来的
- V value = supplier.get();
- if (value != null) {
- return value;
- }
- }
- // else no supplier in cache
- // or a supplier that returned null (could be a cleared CacheValue
- // or a Factory that wasn't successful in installing the CacheValue)
- // lazily construct a Factory
- if (factory == null) {
- factory = new Factory(key, parameter, subKey, valuesMap);
- }
- if (supplier == null) {
- supplier = valuesMap.putIfAbsent(subKey, factory);
- if (supplier == null) {
- // successfully installed Factory
- supplier = factory;
- }
- // else retry with winning supplier
- } else {
- if (valuesMap.replace(subKey, supplier, factory)) {
- // successfully replaced
- // cleared CacheEntry / unsuccessful Factory
- // with our Factory
- supplier = factory;
- } else {
- // retry with current supplier
- supplier = valuesMap.get(subKey);
- }
- }
- }
- }
supplier.get
这个方法中会调用ProxyClassFactory的apply方法,就不过多介绍
ProxyClassFactory.apply
- public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
- Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
- for (Class<?> intf : interfaces) {
- /*
- * Verify that the class loader resolves the name of this interface to the same Class object.
- * 类加载器和接口名解析出的是同一个
- */
- Class<?> interfaceClass = null;
- try {
- interfaceClass = Class.forName(intf.getName(), false, loader);
- } catch (ClassNotFoundException e) {
- }
- if (interfaceClass != intf) {
- throw new IllegalArgumentException( intf + " is not visible from class loader");
- }
- /*
- * Verify that the Class object actually represents an interface.
- * 确保是一个接口
- */
- if (!interfaceClass.isInterface()) {
- throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface");
- }
- /*
- * Verify that this interface is not a duplicate.
- * 确保接口没重复
- */
- if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
- throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName());
- }
- }
- String proxyPkg = null; // package to define proxy class in
- int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
- /*
- * Record the package of a non-public proxy interface so that the proxy class will be defined in the same package.
- * Verify that all non-public proxy interfaces are in the same package.
- * 验证所有非公共的接口在同一个包内;公共的就无需处理
- */
- for (Class<?> intf : interfaces) {
- int flags = intf.getModifiers();
- if (!Modifier.isPublic(flags)) {
- accessFlags = Modifier.FINAL;
- String name = intf.getName();
- int n = name.lastIndexOf('.');
- String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
- if (proxyPkg == null) {
- proxyPkg = pkg;
- } else if (!pkg.equals(proxyPkg)) {
- throw new IllegalArgumentException( "non-public interfaces from different packages");
- }
- }
- }
- if (proxyPkg == null) {
- // if no non-public proxy interfaces, use com.sun.proxy package
- proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
- }
- /*
- * Choose a name for the proxy class to generate.
- * proxyClassNamePrefix = $Proxy
- * nextUniqueNumber 是一个原子类,确保多线程安全,防止类名重复,类似于:$Proxy0,$Proxy1......
- */
- long num = nextUniqueNumber.getAndIncrement();
- String proxyName = proxyPkg + proxyClassNamePrefix + num;
- /*
- * Generate the specified proxy class.
- * 生成类字节码的方法:重点
- */
- byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
- try {
- return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
- } catch (ClassFormatError e) {
- /*
- * A ClassFormatError here means that (barring bugs in the
- * proxy class generation code) there was some other
- * invalid aspect of the arguments supplied to the proxy
- * class creation (such as virtual machine limitations
- * exceeded).
- */
- throw new IllegalArgumentException(e.toString());
- }
- }
ProxyGenerator.generateProxyClass
- public static byte[] generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags) {
- ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
- //真正生成字节码的方法
- final byte[] classFile = gen.generateClassFile();
- //如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数
- //当然,也可以通过返回的bytes自己输出
- if (saveGeneratedFiles) {
- java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() {
- public Void run() {
- try {
- int i = name.lastIndexOf('.');
- Path path;
- if (i > 0) {
- Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
- Files.createDirectories(dir);
- path = dir.resolve(name.substring(i+1, name.length()) + ".class");
- } else {
- path = Paths.get(name + ".class");
- }
- Files.write(path, classFile);
- return null;
- } catch (IOException e) {
- throw new InternalError( "I/O exception saving generated file: " + e);
- }
- }
- });
- }
- return classFile;
- }
最终方法
- private byte[] generateClassFile() {
- /* ============================================================
- * Step 1: Assemble ProxyMethod objects for all methods to generate proxy dispatching code for.
- * 步骤1:为所有方法生成代理调度代码,将代理方法对象集合起来。
- */
- //增加 hashcode、equals、toString方法
- addProxyMethod(hashCodeMethod, Object.class);
- addProxyMethod(equalsMethod, Object.class);
- addProxyMethod(toStringMethod, Object.class);
- //增加接口方法
- for (Class<?> intf : interfaces) {
- for (Method m : intf.getMethods()) {
- addProxyMethod(m, intf);
- }
- }
- /*
- * 验证方法签名相同的一组方法,返回值类型是否相同;意思就是重写方法要方法签名和返回值一样
- */
- for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
- checkReturnTypes(sigmethods);
- }
- /* ============================================================
- * Step 2: Assemble FieldInfo and MethodInfo structs for all of fields and methods in the class we are generating.
- * 为类中的方法生成字段信息和方法信息
- */
- try {
- //增加构造方法
- methods.add(generateConstructor());
- for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
- for (ProxyMethod pm : sigmethods) {
- // add static field for method's Method object
- fields.add(new FieldInfo(pm.methodFieldName,
- "Ljava/lang/reflect/Method;",
- ACC_PRIVATE | ACC_STATIC));
- // generate code for proxy method and add it
- methods.add(pm.generateMethod());
- }
- }
- //增加静态初始化信息
- methods.add(generateStaticInitializer());
- } catch (IOException e) {
- throw new InternalError("unexpected I/O Exception", e);
- }
- if (methods.size() > 65535) {
- throw new IllegalArgumentException("method limit exceeded");
- }
- if (fields.size() > 65535) {
- throw new IllegalArgumentException("field limit exceeded");
- }
- /* ============================================================
- * Step 3: Write the final class file.
- * 步骤3:编写最终类文件
- */
- /*
- * Make sure that constant pool indexes are reserved for the following items before starting to write the final class file.
- * 在开始编写最终类文件之前,确保为下面的项目保留常量池索引。
- */
- cp.getClass(dotToSlash(className));
- cp.getClass(superclassName);
- for (Class<?> intf: interfaces) {
- cp.getClass(dotToSlash(intf.getName()));
- }
- /*
- * Disallow new constant pool additions beyond this point, since we are about to write the final constant pool table.
- * 设置只读,在这之前不允许在常量池中增加信息,因为要写常量池表
- */
- cp.setReadOnly();
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dout = new DataOutputStream(bout);
- try {
- // u4 magic;
- dout.writeInt(0xCAFEBABE);
- // u2 次要版本;
- dout.writeShort(CLASSFILE_MINOR_VERSION);
- // u2 主版本
- dout.writeShort(CLASSFILE_MAJOR_VERSION);
- cp.write(dout); // (write constant pool)
- // u2 访问标识;
- dout.writeShort(accessFlags);
- // u2 本类名;
- dout.writeShort(cp.getClass(dotToSlash(className)));
- // u2 父类名;
- dout.writeShort(cp.getClass(superclassName));
- // u2 接口;
- dout.writeShort(interfaces.length);
- // u2 interfaces[interfaces_count];
- for (Class<?> intf : interfaces) {
- dout.writeShort(cp.getClass(
- dotToSlash(intf.getName())));
- }
- // u2 字段;
- dout.writeShort(fields.size());
- // field_info fields[fields_count];
- for (FieldInfo f : fields) {
- f.write(dout);
- }
- // u2 方法;
- dout.writeShort(methods.size());
- // method_info methods[methods_count];
- for (MethodInfo m : methods) {
- m.write(dout);
- }
- // u2 类文件属性:对于代理类来说没有类文件属性;
- dout.writeShort(0); // (no ClassFile attributes for proxy classes)
- } catch (IOException e) {
- throw new InternalError("unexpected I/O Exception", e);
- }
- return bout.toByteArray();
- }
生成的字节码反编译
- final class $Proxy0 extends Proxy implements pro {
- //fields
- private static Method m1;
- private static Method m2;
- private static Method m3;
- private static Method m0;
- public $Proxy0(InvocationHandler var1) throws {
- super(var1);
- }
- public final boolean equals(Object var1) throws {
- try {
- return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
- } catch (RuntimeException | Error var3) {
- throw var3;
- } catch (Throwable var4) {
- throw new UndeclaredThrowableException(var4);
- }
- }
- public final String toString() throws {
- try {
- return (String)super.h.invoke(this, m2, (Object[])null);
- } catch (RuntimeException | Error var2) {
- throw var2;
- } catch (Throwable var3) {
- throw new UndeclaredThrowableException(var3);
- }
- }
- public final void text() throws {
- try {
- //实际就是调用代理类的invoke方法
- super.h.invoke(this, m3, (Object[])null);
- } catch (RuntimeException | Error var2) {
- throw var2;
- } catch (Throwable var3) {
- throw new UndeclaredThrowableException(var3);
- }
- }
- public final int hashCode() throws {
- try {
- return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
- } catch (RuntimeException | Error var2) {
- throw var2;
- } catch (Throwable var3) {
- throw new UndeclaredThrowableException(var3);
- }
- }
- static {
- 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("spring.commons.api.study.CreateModel.pro").getMethod("text", new Class[0]);
- m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
- } catch (NoSuchMethodException var2) {
- throw new NoSuchMethodError(var2.getMessage());
- } catch (ClassNotFoundException var3) {
- throw new NoClassDefFoundError(var3.getMessage());
- }
- }
- }
java 1.8 动态代理源码分析的更多相关文章
- JDK7动态代理源码分析
IObject proxy = (IObject) Proxy.newProxyInstance(IObject.class.getClassLoader(), new Class[]{IObject ...
- 动态代理学习(二)JDK动态代理源码分析
上篇文章我们学习了如何自己实现一个动态代理,这篇文章我们从源码角度来分析下JDK的动态代理 先看一个Demo: public class MyInvocationHandler implements ...
- jdk 动态代理源码分析
闲来无事,撸撸源码 使用方法 直接看代码吧.. package com.test.demo.proxy; import java.lang.reflect.InvocationHandler; imp ...
- JDK动态代理源码分析
先抛出一个问题,JDK的动态代理为什么不支持对实现类的代理,只支持接口的代理??? 首先来看一下如何使用JDK动态代理.JDK提供了Java.lang.reflect.Proxy类来实现动态代理的,可 ...
- 设计模式之JDK动态代理源码分析
这里查看JDK1.8.0_65的源码,通过debug学习JDK动态代理的实现原理 大概流程 1.为接口创建代理类的字节码文件 2.使用ClassLoader将字节码文件加载到JVM 3.创建代理类实例 ...
- java动态代理源码解析
众所周知,java动态代理同反射原理一直是许多框架的底层实现,之前一直没有时间来分析动态代理的底层源码,现结合源码分析一下动态代理的底层实现 类和接口 java动态代理的主要类和接口有:java.la ...
- 【趣味设计模式系列】之【代理模式2--JDK动态代理源码解析】
1. 图解 上图主要描述了JDK动态代理的执行过程,下面做详细分析. 2. Proxy源码分析 上一篇,在使用JDK动态代理的时候,借助于Proxy类,使用newProxyInstance静态方法,创 ...
- 【趣味设计模式系列】之【代理模式3--Cglib动态代理源码解析】
1. 图解 上图主要描述了Cglib动态代理的主要执行过程,下面做详细分析,以下源码使用的Cglib版本为3.2.12. 2. Enhancer源码分析 public Object create() ...
- JDK动态代理源码学习
继上一篇博客设计模式之代理模式学习之后http://blog.csdn.net/u014427391/article/details/75115928,本博客介绍JDK动态代理的实现原理,学习一下JD ...
随机推荐
- git的使用及常用命令
一,GIT是什么? git是目前世界上最先进的分布式版本控制系统 Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在 ...
- javaweb项目-医者天下 (Spring+SpringMVC+MyBatis)
项目下载地址:http://download.csdn.net/detail/qq_33599520/9826683 项目完整结构图: 项目简介: 医者天下项目是一个基于Spring+SpringMV ...
- .NET遇上Docker - Docker集成Cron定时运行.NETCore(ConsoleApp)程序.md
配置项目的Docker支持 对于VS中Docker的配置,依旧重复一些废话. 给项目添加Docker支持,VS2015可以直接使用Docker for VS插件,VS2017在安装时选择容器支持.VS ...
- & and &&区别
&:位逻辑运算: &&:逻辑运算: &&在java中又称为短路,第一个条件是false的话后面就不执行: &是所有条件都执行: System.out.p ...
- java 无法连接ftp服务器(500 OOPS: cannot change directory)
在使用java连接ftp服务器时可能会出现无法连接的情况,检查代码是没有错误的,这时就应该考虑一下服务器端的情况了: 首先用在本地打开命令窗口,输入:ftp ftp服务器IP,窗口会提示你输入用户名密 ...
- JS基础——循环很重要
介绍循环之前,首先要说一下同样很重要的if-else结构,switch-case结构 ①if-else结构 if(判断条件) { 条件为true时执行 } else{ 条件为false时执行 } ②i ...
- java并发程序——Excutor
概述 Excutor这个接口用的不多,但是ThreadPoolExcutor这个就用的比较多了,ThreadPoolExcutor是Excutor的一个实现.Excutor体系难点没有,大部分的关键点 ...
- idea: 纯 http 上的双向通信
纯 http 上的双向通信 最近大概看了下 rxJava 的订阅者模式,然后突发奇想有没有可能用类似的思路实现纯 http 上的双向通信 A 是传统的 http 服务器 B 是普通的客户端,假设我们能 ...
- logback配置文件详解
一:根节点<configuration>包含的属性: scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod: 设置监测配置文 ...
- PDO(数据访问抽象层)、pdo事务功能和预处理功能---2017-05-05
之前所学的数据访问都是用mysqli做成类来访问的,但是mysqli这个类只是针对mysql这个数据库的:那么如果访问其他类型的数据库呢? 那么这就用到了PDO(数据访问抽象层). 一.关于PDO基本 ...