Java RMI 实现代码动态下载
- 格式:doc
- 大小:35.50 KB
- 文档页数:7
JAVA_RMI使用快速入门Java RMI(Remote Method Invocation,远程方法调用)是一种用于实现分布式系统的Java API,它允许在不同的Java虚拟机上通过网络调用远程对象的方法。
在这篇文章中,我们将快速入门Java RMI,并了解如何使用它来创建一个简单的分布式系统。
1.理解RMI的概念RMI的基本思想是将远程调用看作是本地调用的一种特殊形式,在RMI中,客户端和服务器可以通过网络传输Java对象的引用。
客户端可以通过远程对象的引用来调用它的方法,就像调用本地对象一样。
2.创建远程接口首先,我们需要定义一个远程接口,它列出了远程对象上可用的方法。
这个接口必须扩展java.rmi.Remote接口,并且每个方法都必须声明抛出java.rmi.RemoteException异常。
下面是一个简单的例子:```javaimport java.rmi.Remote;import java.rmi.RemoteException;public interface Hello extends RemoteString sayHello( throws RemoteException;```3.实现远程接口接下来,我们需要实现远程接口,并发布它作为一个RMI对象。
通过扩展java.rmi.server.UnicastRemoteObject类并实现远程接口,我们可以创建一个远程对象。
下面是实现上面接口的一个例子:```javaimport java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class HelloImpl extends UnicastRemoteObject implements Hellopublic HelloImpl( throws RemoteExceptionsuper(;}public String sayHello( throws RemoteExceptionreturn "Hello, world!";}```4.注册远程对象在将远程对象发布到网络之前,我们需要创建一个注册表来管理远程对象的绑定。
JAVA实现下载⽂件功能的两种⽅法第⼀种⽅法:public HttpServletResponse download(String path, HttpServletResponse response) {try {// path是指欲下载的⽂件的路径。
File file = new File(path);// 取得⽂件名。
String filename = file.getName();// 取得⽂件的后缀名。
String ext = filename.substring(stIndexOf(".") + 1).toUpperCase();// 以流的形式下载⽂件。
InputStream fis = new BufferedInputStream(new FileInputStream(path));byte[] buffer = new byte[fis.available()];fis.read(buffer);fis.close();// 清空responseresponse.reset();// 设置response的Headerresponse.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));response.addHeader("Content-Length", "" + file.length());OutputStream toClient = new BufferedOutputStream(response.getOutputStream());response.setContentType("application/octet-stream");toClient.write(buffer);toClient.flush();toClient.close();} catch (IOException ex) {ex.printStackTrace();}return response;}public void downloadLocal(HttpServletResponse response) throws FileNotFoundException {// 下载本地⽂件String fileName = "Operator.doc".toString(); // ⽂件的默认保存名// 读到流中InputStream inStream = new FileInputStream("c:/Operator.doc");// ⽂件的存放路径// 设置输出的格式response.reset();response.setContentType("bin");response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");// 循环取出流中的数据byte[] b = new byte[100];int len;try {while ((len = inStream.read(b)) > 0)response.getOutputStream().write(b, 0, len);inStream.close();} catch (IOException e) {e.printStackTrace();}}public void downloadNet(HttpServletResponse response) throws MalformedURLException {// 下载⽹络⽂件int bytesum = 0;int byteread = 0;URL url = new URL("/logo.gif");try {URLConnection conn = url.openConnection();InputStream inStream = conn.getInputStream();FileOutputStream fs = new FileOutputStream("c:/abc.gif");byte[] buffer = new byte[1204];int length;while ((byteread = inStream.read(buffer)) != -1) {bytesum += byteread;System.out.println(bytesum);fs.write(buffer, 0, byteread);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}第⼆种⽅法:public void downLoad(String filePath, HttpServletResponse response, boolean isOnLine) throws Exception {File f = new File(filePath);if (!f.exists()) {response.sendError(404, "File not found!");return;}BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));byte[] buf = new byte[1024];int len = 0;response.reset(); // ⾮常重要if (isOnLine) { // 在线打开⽅式URL u = new URL("file:///" + filePath);response.setContentType(u.openConnection().getContentType());response.setHeader("Content-Disposition", "inline; filename=" + f.getName());// ⽂件名应该编码成UTF-8} else { // 纯下载⽅式response.setContentType("application/x-msdownload");response.setHeader("Content-Disposition", "attachment; filename=" + f.getName());}OutputStream out = response.getOutputStream();while ((len = br.read(buf)) > 0)out.write(buf, 0, len);br.close();out.close();}以上就是JAVA实现下载⽂件功能的两种⽅法的详细内容,更多关于JAVA实现下载⽂件的资料请关注其它相关⽂章!。
远程方法调用实验报告1.摘要简单介绍了java中的RMI框架的基本原理及应用,给出了java 中创建一个RMI应用的基本步骤。
在此基础上设计了一个采用RMI技术实现远程方法调用的实验,客户端调用服务器端的远程对象的方法,获取服务器端的系统时间,将结果返回客户端。
此外还对实验结果还进行了分析。
2.实验背景RMI采用客户/服务器通信方式。
在服务器上部署了提供各种服务的远程对象,客户端请求访问服务器上的远程对象的方法。
如图1所示,是RemoteServiceClass一个远程对象,它运行在服务器上,客户端请求调用RemoteServiceClass对象的echo()方法。
图1 客户端请求调用服务器上的远程对象的方法如图2所示,RMI采用代理来负责客户和远程对象之间通过Socket进行通信的细节。
RMI框架为远程对象分别生成了客户端代理和服务器端代理。
位于客户端的代理类称为存根(Stub),位于服务器端的代理类称为骨架(Skeleton)。
图2 RMI框架采用代理来封装通信细节当客户端调用远程对象的一个方法时,实际上是调用本地存根对象的相应方法。
存根对象和远程对象具有同样的接口。
存根采用一种与平台无关的编码方式,把方法的参数编码为字节序列,这个编码过程称为参数编组。
RMI主要采用java序列化机制进行参数编组。
接着,存根把请求信息发送给服务器,服务器端接收到客户端的请求信息,然后由相应的骨架对象来处理这一请求信息,把处理后的返回值或者异常编组后发送给客户。
客户端的存根接收到服务器发送过来的编组后的返回值或者异常,再对它进行反编组,就得到调用远程方法的返回结果。
存根与骨架类通过Socket来通信。
开发人员无须手工编写客户端的存根类及服务器端的骨架类,它们都由RMI框架创造。
在JDK5.0以前的版本中,需要用rmic命令来为远程对象生成静态的代理类(包括存根和骨架类)。
而在JDK5.0中,RMI框架会在运行时自动为远程对象生成动态代理类(包括存根和骨架类),从而更彻底封装了RMI 框架的实现细节,简化了RMI框架的使用方式。
Java代码动态编译1. 简介在Java开发中,编写好的代码需要经过编译才能运行。
通常情况下,我们会使用Java的编译器将代码转换成字节码,然后再由Java虚拟机(JVM)执行。
但有时候,我们可能需要在程序运行过程中动态地编译代码,即实现Java代码动态编译。
本文将详细介绍Java代码动态编译的概念、用途和实现方式。
2. 动态编译的概念动态编译是指在程序运行过程中,将一段字符串类型的Java代码转换成可执行的字节码,并且执行该字节码。
相比于传统的静态编译,动态编译允许我们在不修改源代码的情况下,根据特定的需求生成代码并执行。
3. 动态编译的用途动态编译在某些场景下非常有用。
下面列举了几种常见的用途:3.1 插件开发动态编译可以用于插件化开发。
我们可以允许用户在程序运行时加载、卸载和更新插件,而无需重启整个应用程序。
插件以字符串的形式传入,通过动态编译生成可执行的字节码,然后被加载和执行。
3.2 动态织入动态编译还可以用于AOP(面向切面编程)。
在AOP中,我们可以在运行时根据特定规则将切面代码织入到目标代码中,实现类似于日志记录、性能监控等功能。
3.3 脚本语言支持通过动态编译,Java程序可以支持解释脚本语言,比如JavaScript、Groovy等。
这样做的好处是,程序允许用户通过脚本语言编写部分逻辑,动态地加载和执行。
3.4 运行时代码生成有时候我们需要根据特定的需求生成代码,然后立即执行。
动态编译可以满足这一需求。
通过字符串拼接生成代码,然后动态编译执行,可以减少反射等运行时开销。
4. 动态编译的实现方式在Java中,动态编译的实现方式有多种,下面介绍两种常见的方式:4.1 使用Java Compiler APIJava Compiler API允许我们在程序运行时动态地将Java代码编译为字节码。
它提供了一个接口javax.tools.JavaCompiler,通过该接口我们可以获取到Java编译器,并使用它编译代码。
rio枚举过程以下是标题为"RIO枚举过程"的内容:RIO枚举过程RIO (Remote Insecure Object)枚举是一种针对Java RMI(Remote Method Invocation)服务的攻击方式,它利用Java序列化数据的特性来执行任意代码。
RIO枚举的过程主要分为以下几个步骤:1. 扫描目标主机需要扫描目标主机开放的TCP端口,通常Java RMI服务默认监听在1099端口。
可以使用Nmap等工具进行端口扫描。
2. 获取RMI注册表信息如果1099端口开放,就可以尝试连接RMI注册表并获取注册的服务信息。
可以使用各种工具或自己编写代码连接注册表并列出绑定的服务。
3. 下载RMI stub文件从注册表获取到绑定服务的stub文件路径后,就可以下载stub文件。
stub文件包含了服务的接口定义和远程引用信息。
4. 反编译stub文件下载的stub文件是Java字节码格式,需要使用反编译工具(如javap)将其反编译为可读的Java源代码。
5. 寻找可利用的gadget反编译后的Java代码中可能包含一些可利用的gadget(小工具),这些gadget可以被链接在一起形成利用链,从而实现任意代码执行。
6. 构造利用链根据找到的gadget,构造出可以执行任意代码的利用链。
利用链通常是一系列特殊构造的Java对象序列。
7. 触发利用链将构造好的利用链通过RMI服务传递给远程服务端,从而在服务端触发任意代码执行。
RIO枚举过程利用了Java RMI和序列化的特性,需要一定的Java安全知识和代码审计能力。
成功的RIO攻击可以在目标服务器上执行任意命令,从而控制整个系统。
因此,及时修补Java组件漏洞并限制不必要的RMI服务是防御RIO攻击的关键。
java下载功能Java是一种跨平台的编程语言,能够在各种操作系统上运行,因此非常适合用于开发具有下载功能的应用程序。
Java提供了丰富的API和库,使开发者能够轻松地实现下载功能。
下面是一些常用的Java下载功能的实现方式:1. 使用URLConnection类来进行下载:URLConnection类是Java提供的用于网络连接的类,可以通过该类来实现下载。
使用URLConnection的步骤包括创建URL对象、打开连接、获取输入流、创建输出流、将数据从输入流写入输出流等。
2. 使用HttpClient库来进行下载:HttpClient是一个功能强大的开源HTTP客户端库,可以用于发送HTTP请求并处理HTTP响应。
通过使用HttpClient库,可以实现更为复杂的下载功能,例如断点续传、多线程下载等。
3. 使用多线程来进行下载:在下载大文件时,为了加快下载速度,可以使用多线程来并行下载。
通过将文件分成多个部分,每个部分由一个线程负责下载,可以同时下载多个部分,提高下载速度。
4. 使用下载管理器来进行下载:下载管理器是一种用于管理下载任务的工具,可以对下载任务进行管理和控制,例如暂停、取消、进度监控等。
Java提供了一些第三方库,如Downpour 和Download4j,可以用于实现下载管理器。
5. 使用流式处理来进行下载:在Java中,可以使用流式处理来处理大文件的下载。
通过使用BufferedInputStream和BufferedOutputStream,可以将下载的文件分块读取并写入本地文件,避免一次性读取整个文件导致内存溢出。
总之,Java提供了多种方式来实现下载功能,开发者可以根据需求选择合适的方法来实现。
通过合理利用Java的API和库,能够实现高效、安全的下载功能,并提供给用户优质的下载体验。
java跨项目调用方法Java跨项目调用方法背景在开发多个独立的Java项目时,有时我们会遇到需要在一个项目中调用另一个项目中的方法的情况。
这种情况下,我们就需要跨项目进行方法调用。
本文将介绍几种常用的方法来实现Java跨项目调用。
1. 通过Java RMI实现跨项目调用Java RMI(Remote Method Invocation)提供了一种机制,使得一个Java应用可以调用运行在另一个Java虚拟机上的对象的方法。
通过使用Java RMI,我们可以在不同的项目中建立远程连接,实现方法的调用。
使用Java RMI实现跨项目调用的步骤如下:1.定义接口:在被调用项目中定义接口,并在接口中声明需要暴露给其他项目调用的方法。
2.实现接口:在被调用项目中实现接口,并在实现类中实现接口中声明的方法。
3.启动RMI Registry:运行被调用项目时,需要启动RMIRegistry,用于注册被调用对象。
4.注册对象:在被调用项目中,将实现类注册到RMI Registry中,以供其他项目调用。
5.获取远程对象:在调用项目中,通过RMI Registry获取远程对象的引用。
6.调用方法:通过远程对象的引用,调用被调用项目中的方法。
2. 使用WebService实现跨项目调用WebService是一种基于Web的服务技术,通过使用HTTP协议和XML格式进行通信。
我们可以通过在被调用项目中发布一个WebService,然后在调用项目中通过SOAP协议调用WebService的方式实现跨项目方法的调用。
使用WebService实现跨项目调用的步骤如下:1.定义接口:在被调用项目中定义接口,并在接口中声明需要暴露给其他项目调用的方法。
2.实现接口:在被调用项目中实现接口,并在实现类中实现接口中声明的方法。
3.发布WebService:在被调用项目中通过WebService框架(如Apache CXF、Apache Axis等)发布WebService。
java实现调⽤url来下载pdf并且加⽔印,追加excel转成pdf ⽔印jar包:excel转pdf的jar包+license破解认证:第⼀种:使⽤spire.pdf.jar包或者导⼊依赖。
<!--filtutil依赖--><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.2</version></dependency><!--pdf依赖--><dependency><groupId>e-iceblue</groupId><artifactId>spire.pdf.free</artifactId><version>2.2.2</version></dependency><repositories><repository><id>com.e-iceblue</id><name>e-iceblue</name><url>/nexus/content/groups/public/</url></repository></repositories>代码:package pdfwatermark.controller;import com.spire.pdf.PdfDocument;import com.spire.pdf.PdfPageBase;import com.spire.pdf.graphics.*;import lombok.extern.slf4j.Slf4j;import mons.io.FileUtils;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.awt.*;import java.awt.geom.Dimension2D;import java.awt.geom.Point2D;import java.awt.geom.Rectangle2D;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import .HttpURLConnection;import .URL;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.Map;@Slf4j@RestController@RequestMapping(value = "/pdf")public class PdfWaterMark {@ResponseBody@RequestMapping(value = "/loadPdf")public void loadPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {String strUrl = "http://ip:port/apiIn/00000.pdf";URL url = new URL(strUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();//得到输⼊流InputStream inputStream = conn.getInputStream();String[] urlSplit = strUrl.split("/");int i = urlSplit.length;String[] nextSplit = urlSplit[urlSplit.length - 1].split("\\.");//解析出名字String fileName = nextSplit[0];("fileName:" + nextSplit[0]);("localdateTime:" + LocalDateTime.now() + ",localdate" + LocalDate.now());//来使得唯⼀DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");String str = formatter.format(LocalDateTime.now());for (int m = 1; m < 3; m++) {int rd = (int) (Math.random() * 10);str = str + rd;}//保存路径String filePath = "D://" + nextSplit[0] + "-" + str + ".pdf";java.io.File file = new java.io.File(filePath);FileUtils.copyInputStreamToFile(inputStream, file);//获取当前登陆⽤户// Map<String,Object> map = UserController.findCurrentUser(request,response);// String name = (String)map.get("name");waterMark(filePath, "hlh");}public void waterMark(String inputPdf, String waterMarkName) {//创建PdfDocument类的对象PdfDocument pdf = new PdfDocument();//加载测试⽂档pdf.loadFromFile(inputPdf);//获取⽂档第1页PdfPageBase page = pdf.getPages().get(0);pdf.getPages().getCount();//⽂档总页数,就可以对⽂档中所有页数加⽔印,但Spire.pdf.jar免费10页。
java方法跨系统调用方法Java作为一种广泛应用于企业级应用的编程语言,其跨系统调用方法的使用十分重要。
在企业级应用中,常常需要调用其他系统的功能,比如数据库、消息队列等,而跨系统调用方法可以帮助我们方便地实现这些功能。
本文将介绍Java中跨系统调用方法的实现方式。
一、Java中的跨系统调用方法Java中的跨系统调用方法主要有以下几种:1. 远程方法调用(Remote Method Invocation,简称RMI)RMI是Java中的一种机制,允许在不同的Java虚拟机之间进行远程方法调用。
通过RMI,我们可以在一个Java虚拟机中调用另一个Java虚拟机中的对象的方法,而不需要进行任何网络编程。
RMI 使用Java的序列化机制来传递参数和返回值。
2. Java消息服务(Java Message Service,简称JMS)JMS是一种Java中的消息传递规范,用于在不同的Java应用程序之间传递消息。
JMS可以实现点对点通信和发布/订阅通信模式。
在JMS中,消息被发送到一个消息队列中,然后被接收者从队列中读取。
JMS实现了Java应用程序之间的解耦,使得应用程序可以独立地进行开发和部署。
3. Web服务Web服务是一种跨平台、跨语言的服务,可以通过HTTP协议进行调用。
Web服务通常使用SOAP协议进行通信,SOAP是一种基于XML的协议,用于在网络上交换结构化的和可扩展的信息。
通过Web服务,我们可以方便地实现不同系统之间的互操作性。
4. RESTful服务RESTful服务是一种基于HTTP协议的Web服务,它使用HTTP协议中的GET、POST、PUT、DELETE等方法来实现对资源的操作。
RESTful服务主要使用JSON或XML作为数据格式,具有轻量、灵活、易于扩展等特点。
二、实现跨系统调用方法的步骤实现跨系统调用方法的步骤如下:1. 定义接口在调用其他系统的功能时,需要定义一个接口,该接口定义了需要调用的方法和参数。
Java RMI 实现代码动态下载育龙网 WWW.CHINA-B.C0M 2009年06月11日来源:互联网育龙网核心提示:摘要:本译文将向你介绍JavaTMRMI动态类文件下载的应用,学习完本文,你将会对JavaTMRMI有进一步的认识。
希望你能参考我的上一篇译摘要:本译文将向你介绍JavaTMRMI动态类文件下载的应用,学习完本文,你将会对JavaTMRMI有进一步的认识。
希望你能参考我的上一篇译文:开始学习Java RMI,远程方法调用-基础篇。
1.概要Java平台一个重要的优点就是可以动态的从一个给定的URL下载Java软件到一个正在运行JVM的独立进程中,该进程通常位于一个不同物理系统中。
这样可以让一个远程系统运行一个程序,例如一个Applet,它从来没有被安装到本地的存储介质上。
在该文档的前几部分,我们先讨论Applet的codebase,以帮助我们更好的介绍有关Java RMI的codebase.举例来说,一个运行在浏览器中的虚拟机,可以把java.applet.Applet的子类和其相关类的字节码下载下来(到本地)。
运行该浏览器的系统以前从没有运行过该Applet,也没有在本地安装。
一旦所有的类从服务端下载完成,浏览器借助本地资源就开始运行这个Applet程序。
Java RMI正是采用了这个优点,下载、运行这些从来没有在本地安装过的类。
调用Java RMI的API的虚拟机,不仅仅像那些浏览器中,能够下载任意Java类文件,其中含有那些特定Java RMI存根类,它使借助服务器资源的远程调用的执行成为可能。
Codebase观点源于Java程序语言的ClassLoaders的应用。
当一个Java程序使用一个ClassLoader时,那么它需要知道它被允许到那里调用类。
通常,一个类调用者和HTTP Server 一起使用,Server为Java平台应用提供编译过的类。
很可能,你提到第一对有关ClassLoader/codebase就是AppletClassLoader和作为HTML标签<applet的“codebase”属性。
本文档假设你有些Java RMI编程经验,同时写过一些含有applet标签的HTML文件。
例如,在HTML源文件中(applet标签)将含有一些类似下面的代码:<applet height=100 width=100 codebase="myclasses/" code="My.class" <param name="ticker" </applet2.什么是codebase类代码址可以为一个源文件,或是一个目录,虚拟机可以由此加载类。
举个例子来说,如果你邀请一个朋友到家吃晚饭,你需要告诉你朋友你的居住方向,以便你的朋友能够确定你家的位置。
同样,你可以把代码库址(Codebase)看作一个你指给JVM的方向,让JVM能够找到1. 远程对象代码库址(codebase)是通过在远程对象服务端设定java.rmi.server.codebase 属性指定的。
在Java RMI 注册表的帮助下,Java RMI 服务端注册了一个远程对象,并绑定了一个名字。
服务端JVM中代码库址(codebase)设定给在Java RMI注册表中的远程对象引用提供了注解。
2. Java RMI客户端请求一个(已知)命名的远程对象的引用。
客户端使用该引用(远程对象的存根实例)进行对远程对象的方法调用。
3. Java RMI注册表向请求的类返回一个引用(存根实例)。
客户端会优先于codebase在本地的classpath中寻找存根类,如果发现了,那么它就会在本地调用该类。
然而,如果在本地的classpath找不到该stub的存根类,客户端就会试着从远程对象代码库址(codebase)中检索该类。
4. 客户端从代码库址(codebase)请求类。
客户端使用的代码库址(codebase)就是存根实例注解的URL,它是在存根类被注册表加载时注解的。
回到第一步1,为导出对象的存根做注解,然后随着绑定的名字被注册到注册表中。
5. 定义的存根类(和其需要的其他类)被下载到客户端。
注意:第4和5是相同的步骤,当远程对象被一个名字绑定到注册表中时,注册表就开始调用该远程对象类。
当注册表试着调用远程对象的存根类时,从代码库址(codebase)中,它和远程对象一起请求该类的定义。
6. 现在客户端已经具备了调用远程对象方法的所有条件。
存根(在这过程中)像一个服务端的远程对象的代理一样;不像applet使用代码库址(codebase)运行代码在本地的虚拟机中,Java RMI 客户端使用远程的代码库址(codebase)运行代码在另一个,可能是远程JVM 中。
如图三所示:图三:Java RMI 客户端远程方法调用4.在Java RMI中利用codebase属性,实现非存根(sub)类的下载除了下载存根类(stub)和其辅助类到客户端,java.rmi.server.codebase属性还被用来指定其他的,不仅仅是stub类的下载地址。
当客户端调用远程对象的方法时,该方法可能无参或是有许多的参数,根据方法参数类型,这样就可能有三种不同情况发生。
第一种情况,所有的(远程)方法参数(或是返回值)都是原始的数据类型,这样远程对象知道如何的解释他们作为方法的参数,同时也无需检查classpath和codebase属性。
第二种情况,至少有一个参数或是返回值是一个对象,然而远程对象可以在本地的classpath中可以找到该对象类的定义。
第三种情况(如图四,第六步所示),远程方法收到一个对象参数,然而远程对象在本地的classpath中没有找到对象的定义。
这种远程方法的调用情况如图四所示。
客户端发送的对象类可能是(远程方法)参数类的子类型,它可能是两者其中之一:一个接口的实现,该接口为方法的参数(或是返回值)类型一个类的子类,该类为方法的参数(或是返回值)类型图四:Java RMI客户端远程方法调用,传递一个未知的参数类型的子类型类似applet的代码库址(codebase),客户端设定的代码库址(codebase),用于其他JVM下载远程类,非远程类和接口地址。
如果在客户端的应用中设定了代码库址(codebase)属性,那么客户端在调用子类型时,代码库址(codebase)就被作为参数加到子类型的实例上。
如果在客户端没有设定代码库址(codebase),那么远程对象就会错误的使用自己的代码库址(codebase)。
5.命令行例子在applet情况下,代码库址(codebase)是嵌在网页中的,就如我们在本文的第一部分看到的HTML例子。
在Java RMI应用时,codebase不是依靠一个镶嵌在网页中类的引用实现的,客户端会和Java RMI的注册表沟通获得远程对象的应用。
由于远程对象的代码库址(codebase)可以指向任意URL,不能仅是一个相对于已知的URL地址,必须是存根类(stub)和其相关类目录的绝对地址。
代码库址(codebase)可以指向:一个目录地址,该目录中含有类包子目录一个Jar文件路径,含有类包的目录压缩文件满足以上条件的多个目录或是多个Jar文件,中间用空格间隔注意:如果代码库址(codebase)设定为一目录地址,那么结尾一定要是“/”。
例子:如果你把要下载类在“webvector”HTTP服务器的export目录下(在Web根目录下),那么的你的代码库址(codebase)就该这样设置:-Djava.rmi.server.codebase=http://webvector/export/如果你把要下载类放在“webline”HTTP服务器的public目录下(在Web根目录下),一个名字为“mystuff.jar”的Jar文件,你的代码库址(codebase)就该如此设置:-Djava.rmi.server.codebase=http://webline/public/mystuff.jar现在我们假设你把要下载的类分为两个文件“myStuff.jar”和“myOtherStuff.jar”,而且这两个文件放在不同的服务器上(名字是:“webfront”和“webwave”),你的代码库址(codebase)属性就该这样设定:-Djava.rmi.server.codebase="http://webfront/myStuff.jar http://webwave/myOtherStuff.jar"6.疑难问题解答如果你的Java RMI 程序配置正确,任何一个可以序列化的类,包含Java RMI 存根类,都是可以被下载下来的。
动态的存根(stub)能够正常的下载,需要满足几种状况:A. 通过URL提供的存根类和存根类依赖的任何类能够被客户端可达。
B. 在服务程序中通过调用bind或是rebind设定(或是在程序安装的过程中激活)(译注:rebind(String url, Remote obj)或是bind(String url, Remote obj)),如下情况:如步骤A中设定的URL同时如果设定的为一个目录,那么必须是“/”结尾。
C. rmiregistry在它相关的classpath中找不到存根类或是其依赖的其他类。
这也是为什么我们在注册表调用存根时,给它加上代码库址(codebase)的参数的原因了,在服务端或是安装代码中,作为一个调用的结果。
D. 客户端安装的SecurityManager允许存根(stub)下载。
在Java 2 SE或是高版本中,这将意味着客户端必须在策略文件中进行合适的配置。
在使用Java RMI的java.rmi.server.codebase系统变量时,有两种经常性的问题,我们将在下边讨论。
6.1 运行Java RMI服务端可能碰到的问题你碰到的第一个问题可能是收到ClassNotFoundException的异常,当你向注册表绑定(bind或是rebind)一个远程对象和名字时。
这种异常通常是由不合法的codebase属性引起的,导致了在注册表中不能定位远程对象的存根(stub)或是存根需要的其他类。
同远程对象本身相比,远程对象的存根(stub)实现了所有同样的接口,这需要特别的注意。
因此这些接口,同其他定制的类作为方法参数或是返回值,也必须能够通过指定的代码库址(codebase)下载。
通常,由于忽略了属性设定时URL中末尾“/”,导致这个异常的抛出。
其他的一些原因可能是:属性值不是一个URL;URL路径拼写错误或是不正确;设定的URL中存根类(stub)和其相关的类不存在。