- 浏览: 5028757 次
- 性别:
- 来自: 南京
文章分类
- 全部博客 (2844)
- java (1094)
- hadoop (37)
- jvm (39)
- hbase (11)
- sql (25)
- 异常 (83)
- div css (6)
- 数据库 (95)
- 有趣的code (15)
- struts2 (6)
- spring (124)
- js (44)
- 算法 (65)
- linux (36)
- hibernate (7)
- 中间件 (78)
- 设计模式 (2)
- 架构 (275)
- 操作系统 (91)
- maven (35)
- tapestry (1)
- mybatis (9)
- MQ (101)
- zookeeper (18)
- 搜索引擎,爬虫 (208)
- 分布式计算 (45)
- c# (7)
- 抓包 (28)
- 开源框架 (45)
- 虚拟化 (12)
- mongodb (15)
- 计算机网络 (2)
- 缓存 (97)
- memcached (6)
- 分布式存储 (13)
- scala (5)
- 分词器 (24)
- spark (104)
- 工具 (23)
- netty (5)
- Mahout (6)
- neo4j (6)
- dubbo (36)
- canal (3)
- Hive (10)
- Vert.x (3)
- docker (115)
- 分布式追踪 (2)
- spring boot (5)
- 微服务 (56)
- 淘客 (5)
- mesos (67)
- php (3)
- etcd (2)
- jenkins (4)
- nginx (7)
- 区块链 (1)
- Kubernetes (92)
- 驾照 (1)
- 深度学习 (15)
- JGroups (1)
- 安全 (5)
- 测试 (16)
- 股票 (1)
- Android (2)
- 房产 (1)
- 运维 (6)
- 网关 (3)
最新评论
-
明兜3号:
部署落地+业务迁移 玩转k8s进阶与企业级实践技能(又名:Ku ...
Kubernetes系统常见运维技巧 -
q328965539:
牛掰啊 资料收集的很全面
HDFS小文件处理解决方案总结+facebook(HayStack) + 淘宝(TFS) -
guichou:
fluent挂载了/var/lib/kubelet/pods目 ...
kubernetes上部署Fluentd+Elasticsearch+kibana日志收集系统 -
xu982604405:
System.setProperty("java.r ...
jmx rmi 穿越防火墙问题及jmxmp的替代方案 -
大漠小帆:
麻烦问下,“获取每个Item相似性最高的前N个Item”,这个 ...
协同过滤推荐算法在MapReduce与Spark上实现对比
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)//这里有三个参数,第一个是传入classloader,一般情况是传入当前的classloader.但是我在上一节模拟实现里传入的是URL loader..第二个参数表示的是接口,第三个是Invocationhandler,除了第一个参数,其他和我在上一节里的一样.JDK的封装的比较好,所以他传入的是Interface的数组, throws IllegalArgumentException { if (h == null) { throw new NullPointerException();//如果Invocationhandler 为空,抛异常 } /* * Look up or generate the designated proxy class.这个方法里最主要的地方在这里,它直接通过调用 getProxyClass方法获取到了自动生成的动态代理类的二进制码.在我上一节的内容里,我们是通过自己生成JAVA文件,然后通过JAVA文件动态编译成对应的class文件,然后通过URLClassLoader.loadClass("com.cjb.proxy.Proxy1");这个方法来获取对应的二进制码的.这个方法下面会继续解释. */ Class cl = getProxyClass(loader, interfaces); /* * Invoke its constructor with the designated invocation handler.这个方法就是获取对应class的Constructor,然后通过这个Constructor来实例化.. */ try { Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } } 上面的方法,除了最重要的getProxyClass,其他都很容易理解.,那么下面开始读getProxyClass方法 public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded");//JDK想的果然比较到位,连interface传的太多都想到了..~!~ } Class proxyClass = null;//这个就是最后要生成的二进制码,首先初始化一下 /* collect interface names to use as key for proxy class cache */ String[] interfaceNames = new String[interfaces.length];//这个存放的是对应的Interface的名字.. Set interfaceSet = new HashSet(); //这个HashSet 是为了检测interface重复记录的. for (int i = 0; i < interfaces.length; i++) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ String interfaceName = interfaces[i].getName(); Class interfaceClass = null; try { interfaceClass = Class.forName(interfaceName, false, loader);//创建对应接口的二进制码,第二个参数false表示,不需要初始化 } catch (ClassNotFoundException e) { } if (interfaceClass != interfaces[i]) {//如果创建出来的二进制码和原来的接口不一样,表示这个接口对于这个classloader来说是不可见的 throw new IllegalArgumentException( interfaces[i] + " 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.前面说,InterfaceSet是拿来判断对应的interface接口是否有重复的.这里的方法是:在循环interfaces的时候,把每个interface都添加到interfaceSet里..当然,在添加之前会判断,当前循环到的接口在InterfaceSet里是否有,如果已经有了,则抛异常,说这个接口重复了..没有,则添加.. */ if (interfaceSet.contains(interfaceClass)) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } interfaceSet.add(interfaceClass); interfaceNames[i] = interfaceName;//这句就是把每个接口名放到interfaceNames数组里.. } /* * Using string representations of the proxy interfaces as * keys in the proxy class cache (instead of their Class * objects) is sufficient because we require the proxy * interfaces to be resolvable by name through the supplied * class loader, and it has the advantage that using a string * representation of a class makes for an implicit weak * reference to the class. */ Object key = Arrays.asList(interfaceNames);//这里把Interface数组转换成list..这里直接写成了Object类型 /* * Find or create the proxy class cache for the class loader. */ Map cache;//放缓存的Map synchronized (loaderToCache) {//loaderToCache也是一个Map.它的key是classloader,对应的value是对应的缓存,也是一个HashMap.他把对应的不同的classloader放到loaderToCache里,如果下次还要调用这个方法创建代理,并传入的是同一个classloader,那么可以直接从cache里取..增加速度.当然,如果没有,则创建一条记录,放到loaderToCache里 cache = (Map) loaderToCache.get(loader); if (cache == null) { cache = new HashMap(); loaderToCache.put(loader, cache); } /* * This mapping will remain valid for the duration of this * method, without further synchronization, because the mapping * will only be removed if the class loader becomes unreachable. */ } /* * Look up the list of interfaces in the proxy class cache using * the key. This lookup will result in one of three possible * kinds of values: * null, if there is currently no proxy class for the list of * interfaces in the class loader, * the pendingGenerationMarker object, if a proxy class for the * list of interfaces is currently being generated, * or a weak reference to a Class object, if a proxy class for * the list of interfaces has already been generated. */ synchronized (cache) { /* * Note that we need not worry about reaping the cache for * entries with cleared weak references because if a proxy class * has been garbage collected, its class loader will have been * garbage collected as well, so the entire cache will be reaped * from the loaderToCache map. */ do { Object value = cache.get(key);//这里从cache里获取对应的Object..第一次执行的话,明显获取到的是Null..key表示的是用接口名字转换而来的list..这个可以看上面的代码. if (value instanceof Reference) { proxyClass = (Class) ((Reference) value).get();//如果已经能获取到了,那么,我们需要的二进制码文件就是这个获取到的 } if (proxyClass != null) { // proxy class already generated: return it return proxyClass; } else if (value == pendingGenerationMarker) {//这里的pendingGenerationMarker是一个静态常量,表示 new Object().JDK给出的 解释是,如果代理正在创建,那么等待他 // proxy class being generated: wait for it try { cache.wait(); } catch (InterruptedException e) { /* * The class generation that we are waiting for should * take a small, bounded time, so we can safely ignore * thread interrupts here. */ } continue; } else { /* * No proxy class for this list of interfaces has been * generated or is being generated, so we will go and * generate it now. Mark it as pending generation. */ cache.put(key, pendingGenerationMarker);//如果cache里获取到的对应于key的value是Null ,那么,就创建一个object对象放进去.上面说了,pendingGenerationMarker= new Object(); break; } } while (true); } try { String proxyPkg = null; // package to define proxy class in 这个是代理类的包名 /* * 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 (int i = 0; i < interfaces.length; i++) { int flags = interfaces[i].getModifiers();//getModifiers()方法返回的是该接口的修饰类型,用Int类型表示 if (!Modifier.isPublic(flags)) {//如果不是public 的接口.. //我们可以这样理解,我们动态创建的代理,他的修饰类型必须是和接口的修饰类型是一样的,我们知道,接口可以是public或者默认,两种修饰类型.这里的判断如果不是public接口,那么,该接口肯定是默认的,如果是默认修饰类型,那么,它只能被同一个包下面的类看到,所以,就必须为该代理类创建一个包名..当然,如果是public的话,就没必要,因为,反正所有的类都能看到.. String name = interfaces[i].getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1));//注意这里的N+1 ,其实是包括 "."的..比如 com.cjb.proxy.Proxy..它返回的就是"com.cjb.proxy."注意最后的那个点 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,这里可以看到,如果是public 的接口,对应代理类的包名就是"",也就是没有包名 proxyPkg = ""; // use the unnamed package } { /* * Choose a name for the proxy class to generate. */ long num; synchronized (nextUniqueNumberLock) { num = nextUniqueNumber++;//Num是一个计数器.用处是,创建代理的类名的时候用..我们可以看到,它是初始值是0.然后,每被调用一次,Num++. } String proxyName = proxyPkg + proxyClassNamePrefix + num;//proxyPkg是之前生成的包名, proxyClassNamePrefix 是一个静态常量,proxyClassNamePrefix="$Proxy".最后Num是计数器.也就是说,它的代理类的名字是从 $Proxy1 $Proxy2 $Proxy3一直在增长的,这样的话,就避免了重复. /* * Verify that the class loader hasn't already * defined a class with the chosen name. */ /* * Generate the specified proxy class.下面打红字的两个方法是最后生成代理对象的..但是,很悲剧的是,他是用native修饰的,也就是说,它是不是用java来实现的..也就是说,最最关键的地方,不是用java实现的... */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { proxyClass = 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()); } } // add to set of all generated proxy classes, for isProxyClass proxyClasses.put(proxyClass, null); } finally { /* * We must clean up the "pending generation" state of the proxy * class cache entry somehow. If a proxy class was successfully * generated, store it in the cache (with a weak reference); * otherwise, remove the reserved entry. In all cases, notify * all waiters on reserved entries in this cache. */ synchronized (cache) { if (proxyClass != null) { cache.put(key, new WeakReference(proxyClass)); } else { cache.remove(key); } cache.notifyAll(); } } return proxyClass; }
发表评论
-
Kryo 使用指南
2017-12-05 20:14 20071、Kryo 的简介 Kryo 是一个快速序列化/ ... -
spring session序列化问题排查
2017-12-01 19:07 6264严重: Servlet.service() for ser ... -
利用junit对springMVC的Controller进行测试
2017-11-30 16:26 1441平时对junit测试service/D ... -
Java内存模型之重排序
2017-11-29 09:44 858在执行程序时,为了提供性能,处理器和编译器常常会对指令进行重 ... -
pmd spotbugs 文档
2017-11-28 10:02 0https://pmd.github.io/pmd/pmd ... -
PMD、FindBug、checkstyle、sonar这些代码检查工具的区别?各自的侧重点是什么?
2017-11-28 10:01 2142可以说都是代码静态分析工具,但侧重点不同。pmd:基于源代码 ... -
阿里巴巴Java代码规约插件p3c-pmd使用指南与实现解析
2017-11-23 17:09 1602阿里巴巴Java代码规约插件安装 阿里Java代码规 ... -
静态分析工具PMD使用说明 (文章来源: Java Eye)
2017-11-23 17:07 1140质量是衡量一个软件是否成功的关键要素。而对于商业软件系统,尤 ... -
MyBatis 使用 MyCat 实现多租户的一种简单思路
2017-11-20 18:27 2836本文的多租户是基于多数据库进行实现的,数据是通过不同数据库进 ... -
Spring+MyBatis实现数据库读写分离方案
2017-11-20 17:15 1075百度关键词:spring mybatis 多数据源 读写分离 ... -
数据库连接池druid wallfilter配置
2017-11-20 11:38 1335使用缺省配置的WallFilter <be ... -
java restful 实体封装
2017-11-16 09:47 1588package com.mogoroom.bs.commo ... -
dak
2017-11-15 11:21 0package zzm; import jodd.ht ... -
Java内存模型之从JMM角度分析DCL
2017-11-15 09:35 635DCL,即Double Check Lock,中卫双重检查锁 ... -
Java 打印堆栈的几种方法
2017-11-14 09:36 4741java 中可以通过 eclipse 等工具直接打印堆栈, ... -
Servlet Session学习
2017-11-10 09:25 548HTTP 是一种"无状 ... -
浅析Cookie中的Path与domain
2017-11-10 09:26 1057Path – 路径。指定与co ... -
入分析volatile的实现原理
2017-11-08 09:47 682通过前面一章我们了解了synchronized是一个重量级的 ... -
Spring MVC-ContextLoaderListener和DispatcherServlet
2017-11-15 09:35 681Tomcat或Jetty作为Servlet ... -
搭建spring框架的时候,web.xml中的spring相关配置,可以不用配置ContextLoaderListener(即只配DispatcherServl
2017-11-07 18:27 1431搭建spring框架的时候,web.xml中的sprin ...
相关推荐
### 关于JDK动态代理的源码剖析 #### 一、引言 在Java开发过程中,动态代理技术是一项非常实用的技术,它可以帮助我们实现在不修改原有代码的基础上为方法增加额外的功能,比如日志记录、权限校验等。本文将深入...
1. **Java.lang.reflect.Proxy**:这是JDK动态代理的关键类,它提供了创建动态代理对象的工厂方法`newProxyInstance()`。这个方法接收三个参数:`ClassLoader`用于加载代理类,`Interface[]`表示代理对象需要实现的...
首先,JDK动态代理主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。Proxy类用于创建一个代理对象,而InvocationHandler接口则定义了处理代理对象调用方法的逻辑。当调用代理对象的...
JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。Proxy类是生成代理对象的工厂,而InvocationHandler接口定义了调用处理程序的接口,用于处理对代理对象的方法调用...
1. **Proxy类**:这是JDK动态代理的核心类,它提供了`newProxyInstance()`静态方法,用于创建代理对象。 2. **InvocationHandler接口**:每个代理对象都关联一个`InvocationHandler`实例。当代理对象的方法被调用时...
本篇将详细探讨JDK动态代理和Cglib动态代理,并通过源码实例来加深理解。 首先,JDK动态代理是Java内置的一种机制,它依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。`Proxy`类...
标题 "JDK动态代理在EJB3(包括WebService)中的应用" 暗示了本文将探讨Java开发中的一种重要技术——JDK动态代理,以及它如何在企业级JavaBean (EJB) 3.x版本及其相关的Web服务实现中发挥作用。EJB3是Java EE平台的...
源码分析可以揭示其如何实现高效调用,以及如何与Java代理(Proxy)、动态语言支持等特性相互配合。 总之,"JDK8完整源码包"是一个宝贵的学习资源,它涵盖了Java开发的核心技术和优化策略。通过深入研究,开发者不仅...
首先,JDK动态代理主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。JDK动态代理只能为实现了至少一个接口的类生成代理。它的基本原理是利用反射机制生成一个实现了目标接口的...
在这个“jdk动态代理 + 拦截器实现小例”中,我们将探讨如何利用Java的InvocationHandler接口和Proxy类来实现拦截器模式,以实现灵活的代码扩展和日志记录、性能监控等需求。 首先,让我们理解什么是动态代理。在...
java设计模式【之】JDK动态代理【源码】【场景:帮爸爸买菜】.rar /** * 代理模式 * 在开发者的角度来看,创建一个代理对象,提供给用户使用,避免用户直接访问真正的对象 * 在用户角度来看,就是普通的类方法...
JDK动态代理基于Java反射API实现,它提供了`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。`Proxy`类用于创建动态代理实例,而`InvocationHandler`接口则定义了处理方法调用的逻辑。 1....
首先,我们要了解JDK动态代理的核心类——`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`。`Proxy`类用于生成动态代理类,而`InvocationHandler`接口则定义了代理对象处理方法调用的逻辑。 1. ...
JDK和CGlib是两种常用的动态代理实现方式,它们各自有不同的特性和使用场景。 首先,我们来详细了解一下JDK动态代理。JDK动态代理基于接口实现,它要求被代理的对象必须实现至少一个接口。通过`java.lang.reflect....
JDK动态代理主要通过`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`两个类来实现。`Proxy`类是用于生成动态代理类和实例的工具,而`InvocationHandler`接口定义了代理对象处理方法调用的逻辑。 ...
本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...
JDK的动态代理(powernode 文档)(源代码) JDK的动态代理(powernode 文档) 一、动态代理 1.1JDK动态代理 1.1.1 proxy 1.1.2 InvocationHandler 1.1.3 创建一个Maven项目 1.1.4 导入Spring的相关依赖 1.1.5 修改...
在Java编程中,JDK动态代理是一种强大的工具,它允许我们在运行时创建代理类来拦截对目标对象的调用,从而实现额外的功能,比如日志记录、性能监控、事务管理等,而无需修改原始代码。这里我们将深入探讨JDK动态代理...
本文将深入探讨Spring是如何通过JDK的动态代理来实现AOP的。 首先,我们要理解JDK动态代理的基本原理。在Java中,动态代理主要由`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口组成。...