java源代码分析 Java程序分析
JXTA Platform JAVA参考实现源代码分析(2)
引言 管道的概念源于Unix 是不同线程之间直接传输数据的基本手段 JDK中java io包中就有管道类 同时 管道在JXTA中是最基本的概念 是对等点之间的数据传输的主要方式 对等管道协议(PBP)明确规范了对等管道的绑定 解析 响应 本文依次剖析集中式(JDK)和对等环境下(JXTA)管道的实现方式 对比分析其异同 然后尝试在JXTA中建立一个虚拟的全双工的管道 本文的目标是通过对不同环境下管道的实现方式对比分析 来理解为什么JXTA采用管道作为基本的数据传输手段 管道的形象化描述 一个生活中的情景 现在有两个地区A B A是石油生产区 B是石油消费区 现在B地区需要消费A地区的石油 当然可以通过海运 空运获得 然而最通常的方式是架设输油管道 如图所示 引言 管道的概念源于Unix 是不同线程之间直接传输数据的基本手段 JDK中java io包中就有管道类 同时 管道在JXTA中是最基本的概念 是对等点之间的数据传输的主要方式 对等管道协议(PBP)明确规范了对等管道的绑定 解析 响应 本文依次剖析集中式(JDK)和对等环境下(JXTA)管道的实现方式 对比分析其异同 然后尝试在JXTA中建立一个虚拟的全双工的管道 本文的目标是通过对不同环境下管道的实现方式对比分析 来理解为什么JXTA采用管道作为基本的数据传输手段 管道的形象化描述 一个生活中的情景 现在有两个地区A B A是石油生产区 B是石油消费区 现在B地区需要消费A地区的石油 当然可以通过海运 空运获得 然而最通常的方式是架设输油管道 如图所示 java中流的概念和管道的概念都可以通过此案例阐述 A与B之间连接的就是管道 负责将A的石油向B输出 A向管道输出数据(output) B从管道输入数据(input) 可以这样理解 管道是A的输出对象 是B的数据源 这里就产生了三个类 输出流A 输入流B 管道 输入流B负责如何获取数据(read 操作) 输出流A负责如何消费数据(write操作) 管道负责连接它们(connect 操作) 其实 在实现时 管道类分解为管道口 管道出口 由入口出口负责连接 在复杂的网络环境中 这种连接方式可以有专门的网络协议负责(例如 JXTA中的PBP 全称Pipe Bind Protocol) 由以上描述 我们可以清楚知道最原始的管道就是单向的 文章后面介绍的双向管道 是用两个单向管道虚拟的 而非真实的连接方式 不难发现管道最关键的问题是如何协调输出(A)与输入(B) 这在不同的网络环境会遇到不同的问题 最简单的是同一JVM下的不同过程(线程或任务)之间用同步方式传递数据 而对等环境下 如何去发现对方就是一个很现实的问题 这仅仅只是问题的其中之一 下面的章节会依次分析 集中式环境下管道的实现 问题的描述 A与B是在同一JVM中 A B有一方能够发现另一方的存在 A将数据发往B方 A发送数据与B接收数据是相互独立的 现在回到问题的最初 为什么要使用管道?A只管发送 B只管接受 那么数据在哪儿呢?经过下面的分析 就会明白管道把管理数据缓冲区的重任交给了他自己 A B均是围绕这个缓冲区来启停线程的 显然这才是问题的本质 JDK中 类PipeInputStream(即前面所述的B)与PipeOutputStream(即前面所述的的A)可以很好的解决这一问题 首先给出类图如下 下面是将类PipeOutputStream的connect方法代码简化后给予注释 public synchronized void connect(PipedInputStream snk) throws IOException { sink = snk; //将PipeInputStream的实例作为PipeOutputStream的一个属性 以便调用 snk in = ;//缓冲区的输入位置 表示缓冲区为空 snk out = ;//缓冲区的输出位置nnected = true;}连接以后 PipeOutputStream的write操作直接调用sink receive(b);这样 对缓冲区buffer的维护 就变成了read()和receive()操作之间的线程同步 JDK对缓冲区的处理非常巧妙 采用了循环列表 它用缓冲区的标志位的变化来代替数据的移动 类似于生活中的时钟把线性的时间规范为 小时来表示 这不属于本文的论述范围 就不继续分析了 read操作 正常情况下 从out位置读取数据 缓冲区空时进入等待状态 以轮询的方式( 秒间隔)来自我释放 receive操作 正常情况下 向in位置写入数据 缓冲区满时进入等待状态 同样 以轮询的方式( 秒间隔)来自我释放 JXTA对等管道的实现 通过对JDK的分析 我们可以了解到在集中式环境下 管道的架设方案是比较简单的 在对等环境下(分布式环境下也类似) 出于同样的目标 遇到的问题却在急剧的扩大 例如 管道入口和出口之间如何相互发现?数据如何保证在不同的环境下传送?甚至 对管道本身的概念发生质疑 一定是单入口 单出口吗?JXTA规范中 管道是在端点之上的服务或应用之间发送和接收信息的虚拟连接通道 管道提供在对等端点传输之上的网络抽象 管道有点到点和广播两种通信模式 JXTA是通过管道广告来唯一标示管道的 输出管道要找到与其广告相同的输入管道才能发送数据 广告内容如下!DOCTYPE jxta:PipeAdvertisementjxta:PipeAdvertisement xmlns:jxta= ; Idurn:jxta:uuid A E AE ABBE EF CBE /Id Type JxtaUnicast /Type Name PipeExample /Name/jxta:PipeAdvertisement如果您需要对JXTA管道有实例化的概念 请参考Sing Li的使p p能进行交互操作 Jxta命令shell 这篇文章有部分内容专门介绍了如何在通过shell使用管道 本文主要是从编程的视角去看管道是如何实现的 客户视角Project JXTA : Java Programmer s Guide Chapter 有个例子阐述如何去在对等点之间发送信息 读者可以到下载源码 现在从客户视角简要的分析它的传送原理 要深入的了解可以看下一节的系统视角分析 该例中 有两个对等点 并且构建了两个不同的类 一个负责接收(Pipelistener) 一个负责发送(PipeExample) 具体的接收次序可以参考时序图 educity cn/img_ / / / gif 类Pipelistener实现了接口PipeMsgListener 类PipeExample实现了接口OutputPipeListener 由时序图(这是两个JVM中的类 所以时序符号是独立标示的)可以清晰的获知 各个对等点的前 步是相互独立的 各自的第 步 采用回调的方式建立输入和输出管道 一旦对等系统探测到对方的存在 就分别触发各自的事件发送或接收消息 显然JXTA中管道是异步的 调试该例程时 注意先建立输入管道 然后建立输出管道 因为 输出管道在一定的时间和次数内探测不到输入管道的存在 就会主动放弃 否则 容易让网络系统在这些无休止的探测中瘫痪 系统视角从上面的例程中 可以了解对等管道的创建方法 以及数据流程 但是不能明确对等系统是如何去实现的 JXTA中管道的实现比在JDK中实现要复杂得多 具体的技术标准可以参考对等管道绑定协议(PBP) 此协议规范了JXTA中管道的概念 但并没有涉及到如何去实现 这同样是所有JXTA协议的特征 它们的目标是阐述what it is 而把how to do it留给开发者 这样有利于增强系统的开放性 其中Java参考实现 就是该协议实现的一个案例 以下将具体分析 首先看管道实现的类图(以单播为例) educity cn/img_ / / / gif 关键的类 InputPipeImpl 输入管道的实现类 NonBlockingOutputPipe 输出管道的实现类 PipeServiceImpl 管道服务的实现类 负责创建输入输出管道 PipeResolver 提供管道绑定的解析服务 通过客户视角的分析 可以得知系统外部是通过PipeServiceImpl来获取输入输出管道 那么消息是如何在对等系统中通过管道过滤和传递的? 从程序实现的角度 涉及到太多的技术细节 JXTA的参考实现中有着庞杂的监听系统 本文尝试用一个案例从两个层次去解析这个问题 两个层次分别是消息的具体形式 服务和端点协议的具体分发策略 很显然 这里我们把注意力放在了管道的架构路径上 而把如何去架构放在了一边 我想它们是有先后关系的 并且距离并不遥远 案例描述 现在假设有两个对等点alas 和sisal 在一个局域网内 按照客户视角那一节的例程sisal先建立输入管道 alas建立输出管道 由于同一网内可以用广播的方式发送查询信息 可以不设rendevous 并且路由是两点间的 消息传递过程得到了一定的简化 案例分析 以上案例中 从输入输出管道的建立到完成对接并传输数据总共有 个步骤 sisal建立输入管道 alasl建立输出管道 需要查找输入管道 通过广播向网络发出管道查询消息 sisal获得alas的管道查询消息 通过单播向sisal发出响应表示 alas获得sisal的响应 通过单播向alas发出数据 sisal获得数据 lishixinzhi/Article/program/Java/gj/201311/27397
目前成都创新互联公司已为成百上千家的企业提供了网站建设、域名、网站空间、网站托管、企业网站设计、兰陵网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
Java大神如何学习和分析Java框架的源码
1、拿到代码查看项目当中是否有readme这样的文件,如果没有查看是否有文档之类的
2、代码当中没有文档,那么就想你的同事或者其他人要这个框架的介绍或者资料
3、先请教别人这个框架的大体思路
4、自己独立去按照文档或者其他人说的思路去看代码
5、不懂的地方全部记录下面,一次行去问,有的时候很多问题在你看到后面的东西的时候就自然明白了
6、看懂了代码之后自己尝试着写一个,看自己的理解是否正确就这么多了。
如何读JAVA源码
本来不想回答,翻到下面那些答复实在看不过去,就花点功夫整理下吧,希望对有人心能有帮助。
阅读分析源代码,一些有效的方法是:
1、阅读源代码的说明文档和API文档。
2、如果源代码有用法示例或向导,先阅读这个。
3、了解整个项目的模块结构,可以按模块进行阅读。
4、随时使用查找功能(或超链接)阅读关联类或关联方法。
5、对于有疑问的地方,不妨写几行单元测试。
6、由浅入深,由易到难,多阅读优秀的开源项目,代码阅读水平会突飞猛进。
java源代码分析----jvm.dll装载过程
简述 众所周知java exe是java class文件的执行程序 但实际上java exe程序只是一个执行的外壳 它会装载jvm dll(windows下 以下皆以windows平台为例 linux下和solaris下其实类似 为 libjvm so) 这个动态连接库才是java虚拟机的实际操作处理所在 本文探究java exe程序是如何查找和装载jvm dll动态库 并调用它进行class文件执行处理的 源代码 本文分析之代码 《JavaTM SDK Standard Edition v fcsCommunity Source Release》 可从sun官方网站下载 主要分析的源代码为 j se\src\share\bin\java cj se\src\windows\bin\java_md c java c是什么东西 java程序 源代码所谓 java程序 包括jdk中的java exe\javac exe\javadoc exe java c源代码中通过JAVA_ARGS宏来控制生成的代码 如果该宏没定义则编译文件控制生成java exe否则编译文件控制生成其他的 java程序 比如 j se\make\java\javac\Makefile(这是javac编译文件)中 $(CD) / /sun/javac ; $(MAKE) $@ RELEASE=$(RELEASE) FULL_VERSION=$(FULL_VERSION)j se\make\sun\javac\javac\Makefile(由上面Makefile文件调用)中 JAVA_ARGS = { \ J ms m\ \ sun tools javac Main\ } 则由同一份java c代码生成的javac exe程序就会直接调用java类方法 sun tools javac Main 这样使其执行起来就像是直接运行的一个exe文件 而未定义JAVA_ARGS的java exe程序则会调用传递过来参数中的类方法 从java c的main入口函数说起 main()函数中前面一段为重新分配参数指针的处理 然后调用函数 CreateExecutionEnvironment 该函数主要查找java运行环境的目录 和jvm dll这个虚拟机核心动态连接库文件路径所在 根据操作系统不同 该函数有不同实现版本 但大体处理逻辑相同 我们看看windows平台该函数的处理(j se\src\windows\bin\java_md c) CreateExecutionEnvironment函数主要分为三步处理 a 查找jre路径 b 装载jvm cfg中指定的虚拟机动态连接库(jvm dll)参数 c 取jvm dll文件路径 实现 a 查找jre路径是通过java_md c中函数 GetJREPath实现的 该函数首先调用GetApplicationHome函数 GetApplicationHome函数调用windowsAPI函数GetModuleFileName取java exe程序的绝对路径 以我的jdk安装路径为例 为 D:\java\j sdk _ \bin\java exe 然后去掉文件名取绝对路径为 D:\java\j sdk _ \bin 之后会在去掉最后一级目录 现在绝对路径为 D:\java\j sdk _ 然后GetJREPath函数继续判断刚刚取的路径+\bin\java dll组合成的这个java dll文件是否存在 如果存在则 D:\java\j sdk _ 为JRE路径 否则判断取得的 D:\java\j sdk _ 路径+\jre\bin\java dll文件是否存在 存在则 D:\java\j sdk _ \jre 为JRE路径 如果上面两种情况都不存在 则从注册表中去查找(参见函数GetPublicJREHome) 函数 GetPublicJREHome先查找 HKEY_LOCAL_MACHINE\Sofare\JavaSoft\Java Runtime Environment\CurrentVersion键值 当前JRE版本号 判断 当前JRE版本号 是否为 做为版本号 如果是则取HKEY_LOCAL_MACHINE\Sofare\JavaSoft\Java Runtime Environment\ 当前JRE版本号 \JavaHome的路径所在为JRE路径 我的JDK返回的JRE路径为 D:\java\j sdk _ \jre b 装载jvm cfg虚拟机动态连接库配置文件是通过java c中函数:ReadKnownVMs实现的 该函数首先组合jvm cfg文件的绝对路径 JRE路径+\lib+\ARCH(CPU构架)+\jvm cfgARCH(CPU构架)的判断是通过java_md c中GetArch函数判断的 该函数中windows平台只有两种情况 WIN 的 ia 其他情况都为 i 我的为i 所以jvm cfg文件绝对路径为 D:\java\j sdk _ \jre\lib\i \jvm cfg 文件内容如下 ## @(#)jvm cfg / / # # Copyright Sun Microsystems Inc All rights reserved # SUN PROPRIETARY/CONFIDENTIAL Use is subject to license terms # # ### List of JVMs that can be used as an option to java javac etc # Order is important first in this list is the default JVM # NOTE that this both this file and its format are UNSUPPORTED and# WILL GO AWAY in a future release ## You may also select a JVM in an arbitrary location with the# XXaltjvm=jvm_dir option but that too is unsupported# and may not be available in a future release # client KNOWN server KNOWN hotspot ALIASED_TO client classic WARN native ERROR green ERROR(如果细心的话 我们会发现在JDK目录中我的为 D:\java\j sdk _ \jre\bin\client 和 D:\java\j sdk _ \jre\bin\server 两个目录下都存在jvm dll文件 而java正是通过jvm cfg配置文件来管理这些不同版本的jvm dll的 )ReadKnownVMs函数会将该文件中的配置内容读入到一个JVM配置结构的全局变量中 该函数首先跳过注释(以 # 开始的行) 然后读取以 开始的行指定的jvm参数 每一行为一个jvm信息 第一部分为jvm虚拟机名称 第二部分为配置参数 比如行 client KNOWN 则 client 为虚拟机名称 而 KNOWN 为配置类型参数 KNOWN 表示该虚拟机的jvm dll存在 而 ALIASED_TO 表示为另一个jvm dll的别名 WARN 表示该虚拟机的jvm dll不存在但运行时会用其他存在的jvm dll替代执行 而 ERROR 同样表示该类虚拟机的jvm dll不存在且运行时不会找存在的jvm dll替代而直接抛出错误信息 在运行java程序时指定使用那个虚拟机的判断是由java c中函数 CheckJvmType判断 该函数会检查java运行参数中是否有指定jvm的参数 然后从ReadKnownVMs函数读取的jvm cfg数据结构中去查找 从而指定不同的jvm类型(最终导致装载不同jvm dll) 有两种方法可以指定jvm类型 一种按照jvm cfg文件中的jvm名称指定 第二种方法是直接指定 它们执行的方法分别是 java Jjvm cfg中jvm名称 java XXaltjvm=jvm类型名称 或 java J XXaltjvm=jvm类型名称 如果是第一种参数传递方式 CheckJvmType函数会取参数 J 后面的jvm名称 然后从已知的jvm配置参数中查找如果找到同名的则去掉该jvm名称前的 直接返回该值 而第二种方法 会直接返回 XXaltjvm= 或 J XXaltjvm= 后面的jvm类型名称 如果在运行java时未指定上面两种方法中的任一一种参数 CheckJvmType会取配置文件中第一个配置中的jvm名称 去掉名称前面的 返回该值 CheckJvmType函数的这个返回值会在下面的函数中汇同jre路径组合成jvm dll的绝对路径 比如 如果在运行java程序时使用 java J client test 则ReadKnownVMs会读取参数 client 然后查找jvm cfg读入的参数中是否有jvm名称为 client 的 如果有则去掉jvm名称前的 直接返回 client 而如果在运行java程序时使用如下参数 java XXaltjvm=D:\java\j sdk _ \jre\bin\client test 则ReadKnownVMs会直接返回 D:\java\j sdk _ \jre\bin\client 如果不带上面参数执行如 java test 因为在jvm cfg配置文件中第一个存在的jvm为 client 所以函数ReadKnownVMs也会去掉jvm名称前的 返回 client 其实这三中情况都是使用的 D:\java\j sdk _ \jre\bin\client\jvm dll 这个jvm动态连接库处理test这个class的 见下面GetJVMPath函数 c 取jvm dll文件路径是通过java_md c中函数 GetJVMPath实现的 由上面两步我们已经获得了JRE路径和jvm的类型字符串 GetJVMPath函数判断CheckJvmType返回的jvm类型字符串中是否包含了 \ 或 / 如果包含则以该jvm类型字符串+\jvm dll作为JVM的全路径 否则以JRE路径+\bin+\jvm类型字符串+\jvm dll作为JVM的全路径 看看上面的例子 第一种情况 java J client test jvm dll路径为 JRE路径+\bin+\jvm类型字符串+\jvm dll 按照我的JDK路径则为 D:\java\j sdk _ \jre + \bin + \client + \jvm dll 第二种情况 java XXaltjvm=D:\java\j sdk _ \jre\bin\client test 路径为 jvm类型字符串+\jvm dll即为 D:\java\j sdk _ \jre\bin\client + \jvm dll 第三种情况 java test 为 D:\java\j sdk _ \jre + \bin + \client + \jvm dll 与情况一相同 所以这三种情况都是调用的jvm动态连接库 D:\javaj sdk _ \jre\bin\client\jvm dll 处理test类的 我们来进一步验证一下 打开cmd控制台 设置java装载调试E:\work\java_researchset _JAVA_LAUNCHER_DEBUG= 情况一E:\work\java_researchjava J client test ScanDirectory _JAVA_LAUNCHER_DEBUG lishixinzhi/Article/program/Java/hx/201311/26750
java源代码分析 实在是不太会,求高手教教我。
package test2;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class JavaCodeAnalyzer {
public static void analyze(File file) throws IOException{
//FileOutputStream fos = new FileOutputStream("F;"+File.separator+"result.txt");
if(!(file.getName().endsWith(".txt")||file.getName().endsWith(".java"))){
System.out.println("输入的分析文件格式不对!");
}
InputStream is= new FileInputStream(file);
BufferedReader br= new BufferedReader(new InputStreamReader(is));
String temp;
int count=0;
int countSpace=0;
int countCode=0;
int countDesc=0;
MapString, Integer map = getKeyWords();
while((temp=br.readLine())!=null){
countKeys(temp, map);
count++;
if(temp.trim().equals("")){
countSpace++;
}else if(temp.trim().startsWith("/*")||temp.trim().startsWith("//")){
countDesc++;
}else{
countCode++;
}
}
System.out.printf("代码行数:"+countCode+"占总行数的%4.2f\n",(double)countCode/count);
System.out.printf("空行数:"+countSpace+"占总行数的%4.2f\n",(double)countSpace/count);
System.out.printf("注释行数:"+countDesc+"占总行数的%4.2f\n",(double)countDesc/count);
System.out.println("总行数:"+count);
System.out.println("出现最多的5个关键字是:");
System.out.println("");
System.out.println("");
System.out.println("");
System.out.println("");
System.out.println("");
}
public static void main(String[] args) {
getKeyWords();
File file = new File("F://Test.java");
try {
analyze(file);
} catch (IOException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
public static MapString,Integer getKeyWords(){
MapString,Integer map = new HashMapString, Integer();
String[]keywords = {"abstract","assert","boolean","break","byte","case","catch","char","class","continue","default","do","double","else","enum","extends","final","finally","float","for","if","implements","import","instanceof","int","interface","long","native","new","package","private","protected","public","return"," strictfp","short","static","super"," switch","synchronized","this","throw","throws","transient","try","void","volatile","while","goto","const"};
for(String s:keywords){
map.put(s, 0);
}
return map;
}
public static void countKeys(String s,MapString,Integer map){
SetString keys = map.keySet();
for(String ss:keys){
if(s.indexOf(ss)!=-1){
map.put(ss, map.get(ss)+1);
}
}
}
}
上班没啥时间了,还有点没写完,你在想想。
网站题目:java源代码分析 Java程序分析
新闻来源:http://myzitong.com/article/hghdjp.html