java在远程方法调用中运用反射机制详解

KLQ 2020-08-25 09:24:53 java常见问答 6148

之前给大家介绍了java通过反射访问成员变量的内容,下面要接着给大家介绍java在远程方法调用中运用反射机制方面的知识,一起来了解一下。

在本文当中,将会详细的介绍反射机制在网络编程中的应用,实现怎样在客户端通过远程方法调用服务器端的方法。

假设,在服务器端有一个HelloService接口,这个接口具有getTime()和echo()方法。

代码:

import java.util.Date;
public interface HelloService
{
    public String echo(String msg);
    public Date getTime();
}

在服务器上面创建一个HelloServiceImpl类,并实现HelloService接口,HelloServiceImpl类的代码:

import java.util.Date;
public class HelloServiceImpl implements HelloService
{
    @Override
    public String echo(String msg)
    {
        return "echo:" + msg;
    }
    @Override
    public Date getTime()
    {
        return new Date();
    }
}

在上面的代码当中,在HelloServiceImpl类当中,对echo()方法和getTime()方法进行了重写,那么,客户端怎样调用服务器端Hello-ServiceImpl类中的getTime() 和 echo()方法呢?

下面是具体方法:

客户端要将调用的方法名、方法参数类型、方法参数值,以及方法所属的类名或接口名发送给服务器端,服务器端再调用相关对象的方法,之后,在将方法的返回值发送给客户端。

为了可以方便的按照面向对象的方式来处理客户端与服务器端的通信,可以把它们发送的信息用Call类来表示,一个Call对象表示客户端发起的一个远程调用,它包括了调用的类名或接口名、方法名、方法参数类型、方法参数值和方法执行结果。

Call类的实现代码:

import java.io.Serializable;
public class Call implements Serializable
{
    private static final long serialVersionUID = 6659953547331194808 L;
    private String className; // 表示类名或接口名
    private String methodName; // 表示方法名
    private Class[] paramTypes; // 表示方法参数类型
    private Object[] params; // 表示方法参数值
    // 表示方法的执行结果
    // 如果方法正常执行,则result为方法返回值,如果方法抛出异常,那么result为该异常。
    private Object result;
    public Call()
    {}
    public Call(String className, String methodName, Class[] paramTypes, Object[] params)
    {
        this.className = className;
        this.methodName = methodName;
        this.paramTypes = paramTypes;
        this.params = params;
    }
    public String getClassName()
    {
        return className;
    }
    public void setClassName(String className)
    {
        this.className = className;
    }
    public String getMethodName()
    {
        return methodName;
    }
    public void setMethodName(String methodName)
    {
        this.methodName = methodName;
    }
    public Class[] getParamTypes()
    {
        return paramTypes;
    }
    public void setParamTypes(Class[] paramTypes)
    {
        this.paramTypes = paramTypes;
    }
    public Object[] getParams()
    {
        return params;
    }
    public void setParams(Object[] params)
    {
        this.params = params;
    }
    public Object getResult()
    {
        return result;
    }
    public void setResult(Object result)
    {
        this.result = result;
    }
    public String toString()
    {
        return "className=" + className + "methodName=" + methodName;
    }
}

假设,客户端为SimpleClient,服务器端为SimpleServer,SimpleClient调用SimpleServer的HelloServiceImpl对象中echo()方法的流程如下所示:

SimpleClient调用SimpleServer的HelloServiceImpl对象中echo()方法的流程

下面先来看一下客户端程序SimpleClient类的实现代码:

import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class SimpleClient
{
    public void invoke() throws Exception
    {
        Socket socket = new Socket("localhost", 8000);
        OutputStream out = socket.getOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(out);
        InputStream in = socket.getInputStream();
        ObjectInputStream ois = new ObjectInputStream( in );
        // 创建一个远程调用对象
        Call call = new Call("ch12.HelloService", "echo", new Class[]
        {
            String.class
        }, new Object[]
        {
            "Java"
        });
        oos.writeObject(call); // 向服务器发送Call对象
        call = (Call) ois.readObject(); // 接收包含了方法执行结果的Call对象
        System.out.println(call.getResult());
        ois.close();
        oos.close();
        socket.close();
    }
    public static void main(String args[]) throws Exception
    {
        new SimpleClient()
            .invoke();
    }
}

正如上面的代码一样,客户端SimpleClient类的主要作用是建立和服务器的连接,之后把带有调用信息的Call对象发送到服务器端。

服务器端SimpleServer类在收到调用请求以后,会使用反射机制动态调用指定对象的指定方法,再将执行结果返回给客户端。

SimpleServer类的实现代码:

import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;
public class SimpleServer
{
    private Map remoteObjects = new HashMap(); // 存放远程对象的缓存
    /** 把一个远程对象放到缓存中 */
    public void register(String className, Object remoteObject)
    {
        remoteObjects.put(className, remoteObject);
    }
    public void service() throws Exception
    {
        ServerSocket serverSocket = new ServerSocket(8000);
        System.out.println("服务器启动.");
        while (true)
        {
            Socket socket = serverSocket.accept();
            InputStream in = socket.getInputStream();
            ObjectInputStream ois = new ObjectInputStream( in );
            OutputStream out = socket.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(out);
            Call call = (Call) ois.readObject(); // 接收客户发送的Call对象
            System.out.println(call);
            call = invoke(call); // 调用相关对象的方法
            oos.writeObject(call); // 向客户发送包含了执行结果的Call对象
            ois.close();
            oos.close();
            socket.close();
        }
    }
    public Call invoke(Call call)
    {
        Object result = null;
        try
        {
            String className = call.getClassName();
            String methodName = call.getMethodName();
            Object[] params = call.getParams();
            Class classType = Class.forName(className);
            Class[] paramTypes = call.getParamTypes();
            Method method = classType.getMethod(methodName, paramTypes);
            Object remoteObject = remoteObjects.get(className); // 从缓存中取出相关的远程对象
            if (remoteObject == null)
            {
                throw new Exception(className + "的远程对象不存在");
            }
            else
            {
                result = method.invoke(remoteObject, params);
            }
        }
        catch (Exception e)
        {
            result = e;
        }
        call.setResult(result); // 设置方法执行结果
        return call;
    }
    public static void main(String args[]) throws Exception
    {
        SimpleServer server = new SimpleServer();
        // 把事先创建的HelloServiceImpl对象加入到服务器的缓存中
        server.register("ch13.HelloService", new HelloServiceImpl());
        server.service();
    }
}

因为,这是一个网络程序,所以,首先的话就要运行服务器端SimpleServer,之后,再运行客户端SimpleClient,运行结果是在客户端看到输出“echoJava”,这个结果是服务器端执行HelloServicelmpl对象的echo() 方法的返回值。

下面是SimpleClient和SimpleServer的通信过程:

SimpleClient和SimpleServer的通信过程

关于java在远程方法调用中运用反射机制你都了解了吗?希望上面的内容能够对你有所帮助呢,假如,你还想了解更多和java反射方面相关的java基础知识,那么就请继续关注奇Q工具网来进行了解学习吧。

推荐阅读:

java通过反射执行方法详解

java通过反射访问构造方法详解

java反射机制API详解