2008年4月10日

1.       书目

精通RMI——Java与EJB企业级应用开发

Java™ RemoteMethodInvocation Specification

Java tutorial- RMI

2.       基础知识

2.1 网络通信协议

网络通信层是分布式计算环境中使用客户/服务器结构的一个核心技术,而网络编程中大体有两种通信模式,无连接和面向连接的协议。

             UDP

UDP (universal datagram protocol)是一种用于无连接通信的标准化协议,其建立在IP协议之上,而IP协议是internet使用的基本数据传输协议。UDP协议的主要作用是将网络数据流量压缩成数据报文的形式。一个典型的数据报文就是一个二进制数据的传输单位。每一个数据报的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。UDP协议并不提供数据传送的保证机制。如果在从发送方到接收方的传递过程中出现数据报的丢失,协议本身并不能做出任何检测或提示。因此,通常人们把UDP协议称为不可靠的传输协议。一般用来传输少量数据,它资源消耗小,处理速度快。

 TCP

TCP(transport control protocol)传输控制协议,标准化的面向连接的通信协议。在使用TCP协议中发送者和接收者必须在通信之前建立连接,连接建立之后被看成是一个数据流,发送者将数据发到该数据流上,接收者从该数据流上读取数据。如果接收者也同时是发送者则连接是双向的。通信完成后任何一方都可以关闭连接,之后的读写操作都会失败。TCP协议提供了可靠的面向对象的数据流传输服务的规则和约定。简单的说在TCP模式中,对方发一个数据包给你,你要发一个确认数据包给对方。Java提供的类库都将TCP/IP协议的使用借助套接字(Socket)进行了抽象。套接字包含了建立与远程主机的连接,与主机进行通信以及关闭连接所需要的所有操作,而这些操作实际上还是由TCP/IP来执行的。

编组

在应用复杂尤其是面向对象的时候,一方面会遇到处理数据或者对象的结构的问题。另一方面还会遇到面向流的用来发送字节或字符块的网络连接问题。此时需要将对象转换成连接可以处理的格式,从而使自定义的对象可以通过连接管道。

编组(marshalling)是一个将负责对象转换成字节流的过程,然后在使用反过程----反编组将字节流转换成对象。Java中编组的实现方式是序列化(serialization)。


    代理

代理是一个实现给定接口的对象,但是不直接执行一些代码计算结果,而是代表其他一些对象执行实际计算的对象。


    
    代理可以代表其他的库或者某种类似的可以代替它执行网络通信的东西。这就是RMI工作的原理,代理在RMI也即存根(Stub)。

引用位于服务器中的对象的代理是如何构造的?客户端不能有一个真的Java引用,因为Java引用只在对象位于同一个JVM时才能正常工作。构造的基本思想是为服务器对象分配一个唯一的标识序号,该序号由代理保存,此外还有对象所在的主机名。



    客户如何请求代理

在获取代理时我们需要一个间接层把所有细节抽象,通过使用名字去获得对应对象的思想就是命名。命名的一个主要作用是通过使用对象的名字,简化获得对象的任务。

对于RMI来说,最通用的命名实现时RMI注册,它具有bind和lookup操作,对于命名服务来说,客户端其实存在一个它的代理。

命名使用示例图

posted @ 2009-05-19 21:37 迟来的兵 阅读(452) | 评论 (0)编辑 收藏

一.String对象的比较,+操作和intern方法
这里从一个问题入手来看看。

package testPackage;
   public class Test {
        
public static void main(String[] args) {
            String hello 
= "Hello", lo = "lo";
            System.out.print((hello 
== "Hello"+ " ");
            System.out.print((Other.hello 
== hello) + " ");
            System.out.print((other.Other.hello 
== hello) + " ");
            System.out.print((hello 
== ("Hel" + "lo")) + " ");
            System.out.print((hello 
== ("Hel" + lo)) + " ");
            System.out.println(hello 
== ("Hel" + lo).intern());
        }

    }
    class Other {
        
static String hello = "Hello";
    }


package other;
    public class Other {
        
static String hello = "Hello";
    }

正确答案:true true true true false true
主要要点有:
1.所有内容相同的String指向同一个内存块。但String对象不能是通过new操作创建出来。主要原因是JVM对String做了优化,String加载之后会持有一个常量池,
只要在常量池中找到内容相同的String就会把其引用返回。而new操作是直接在内存中分配新空间。



2.Java中有两种绑定,静态和动态。如果+操作的两边是常量表达式那么会在采用静态绑定,也就是说编译之后值已经定下来了。而如果有一边是通过new操作创建出
来的那么会采用动态绑定,只有在运行的时候才知道其具体的值。
3.String的intern方法会到常量池里面找是否有相同内容的String,如果有则返回其引用。如果没有则把这个String对象添加到常量池之中并放回其引用。额外说
下,intern在英文中有保留区的意思,这样好理解其作用。intern方法还是native的。
二.String中的正则表达式使用

String中有些方法是需要正则表达式作为参数的。这个时候就要主要不要传错参数。最典型的例子就是replaceAll(String regex, String replacement)。第一个
参数是需要正则表达式的,而第二参数是普通的字符串。
        String ss = "???";
        ss 
= ss.replaceAll("?""=");//运行到这里会抛出PatternSyntaxException,因为“?”在正则表达式里面是特殊符号,需要转义。
        ss = ss.replaceAll("[?]""=");//正确,我个人比较倾向于这种写法。
        ss = ss.replaceAll("\\?""=");//正确,对“?”做转义。

因此在使用split,replaceAll,replaceFirst等方法时要特别注意是不是需要转义.

posted @ 2008-12-06 19:39 迟来的兵 阅读(227) | 评论 (0)编辑 收藏

1.优先使用primitive type
2.不要使用Boolean作为返回值。
3.在初始化所有变量之后再创建类的实例。
4. 用URI代替URL,使用URI的create方法代替new。
5. 注意使用inputsream的skip方法,此方法会返回实际跳过的长度,最好自己监听返回值。
6. ?:运算符会返回最大范围的类型,如:true?new Intege(2): new Float(1.0);将会返回2.0.
7. 尽量使用double,而不是float。

posted @ 2008-04-21 19:24 迟来的兵 阅读(214) | 评论 (0)编辑 收藏

1. interface来定义系统对外提供的服务,有抽象类来做扩展。尽量用interface作为参数类型。

2. ThreadLocal类,定义了一个变量的本地副本,与原有变量隔离,作用类似static变量,只是不共享。可用set添加变量,get去获取变量。变量类型不限制。

3. Eclipse plug in开发中可以实现IRuntimeClasspathProvider接口。可以提供用launch configuration去获得unresolvedresolved classpath。开发人员可以在resolveClasspath方法中加入自定义的classpath。实现类需要注册在extension point中。

      /**

       *Computesandreturnsanunresolvedclasspathforthegivenlaunchconfiguration.

       *Variableandcontainerentriesarenotresolved.

       *

       *@paramconfigurationlaunchconfiguration

       *@returnunresolvedpath

       *@exceptionCoreExceptionifunabletocomputeapath

       */

      public IRuntimeClasspathEntry[] computeUnresolvedClasspath(ILaunchConfiguration configuration) throws CoreException;

     

      /**

       *Returnstheresolvedpathcorrespondingtothegivenpath,inthecontextofthe

       *givenlaunchconfiguration.Variableandcontainerentriesareresolved.Thereturned

       *(resolved)pathneednothavethesamenumberofentriesasthegiven(unresolved)

       *path.

       *

       *@paramentriesentriestoresolve

       *@paramconfigurationlaunchconfigurationcontexttoresolvein

       *@returnresolvedpath

       *@exceptionCoreExceptionifunabletoresolveapath

       */

      public IRuntimeClasspathEntry[] resolveClasspath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException;

A provider extension is defined in plugin.xml. Following is an example definition of a runtime classpath provider extension.

 <extension point="org.eclipse.jdt.launching.classpathProviders">
   <classpathProvider 
      id="com.example.ExampleClasspathProvider"
      class="com.example.ExampleClasspathProviderImpl"
   </classpathProvider>
 </extension>

4. plug in 开发中可以用JavaRuntime 去得到运行环境的信息。        
IRuntimeClasspathProvider provider = JavaRuntime
.getClasspathProvider(configuration);

其中configurationILaunchConfiguration类型的。

4. Eclipse plug in开发中获取文件。两种解决办法:1.plug in实例中读取文件的URL,然后用FileLocator把这个URL转化成文件路径;2.直接利用FileLocatorfind方法。

方法1

            //filepath 是需要定位的文件

            String filepath = "/bin/resources/test.jar";

            //instance 是当前plug in的实例

            URL url = instance.getBundle().getEntry(filepath);

            String path = null;

            try {

                  path = FileLocator.resolve(url).getPath();

            } catch (IOException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

            }

            returnnew Path(path);

      }

方法2

            String filepath = "/bin/resources/test.jar";

            URL url = FileLocator.find(instance.getBundle(),new Path(filepath),null);

            try {

                  path = FileLocator.resolve(url).getPath();

            } catch (IOException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

            }

5. 可以利用JarOutputStream来写jar包。必须为JarOutputStream 实例创建至少一个Entry,可以调用putNextEntry方法。

            Manifest mf = new Manifest();

            JarOutputStream jar = new JarOutputStream(new FileOutputStream("MainTest.jar")mf);

            Properties properties = new Properties();

            jar.putNextEntry(new ZipEntry("MainTest.property"));

            properties.store(jar, "this is a test");

            jar.close();

6. 得到IJavaModle

      IJavaModel model = JavaCore.create(ResourcesPlugin.getWorkspace()

                              .getRoot());

      IJavaProject[] projects = model.getJavaProjects();

      IPackageFragmentRoot[] roots = projects[i]                                          .getPackageFragmentRoots();

 然后可以依次得到对应elements

posted @ 2008-04-10 17:12 迟来的兵 阅读(553) | 评论 (0)编辑 收藏


posts - 6, comments - 8, trackbacks - 0, articles - 1

Copyright © 迟来的兵