EJB分布式工作原理

因为涉及到网络传送,所以对象肯定是序列化传送的,但是我们在ejb3.0中自己定义的会话bean等却没有实现可序列化接口,为什么呢,

这是因为,ejb采用的是rmi(Remote Method Invocation)实现的,因为rmi已经封装好传递的细节,所以我们来看一下rmi的工作原理这样我们

就可以大概了解ejb的分布式调用原理了,RMI的本质就是实现在不同JVM之间的调用,它的实现方法就是在两个JVM中各开一个Stub和Skeleton,二者通过socket通信来实现参数和返回值的传递。

jmi使用小实例:

接口:

package senssic.ejb.imitate;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface JmiDemoBean extends Remote {
	public String sayHello() throws RemoteException;
}

实现类:

package senssic.ejb.imitate;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class JmiDemoBeanImpl extends UnicastRemoteObject implements JmiDemoBean {
        //必须继承UnicastRemoteObject类,不然报错,因为UnicastRemoteObject 实现了底层细节,需要继承
	// 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,必须声明抛出RemoteException异常
	protected JmiDemoBeanImpl() throws RemoteException {
		super();
		// TODO Auto-generated constructor stub
	}

	@Override
	public String sayHello() throws RemoteException {

		return "你好世界";
	}

}

服务端:

package senssic.ejb.imitate;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

public class JmiDemoSer {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			// 创建一个远程对象
			JmiDemoBean jmiImpl = new JmiDemoBeanImpl();
			// 本地主机上的远程对象注册表Registry的实例,并指定端口为8888,缺少注册表创建,则无法绑定对象到远程注册表上
			LocateRegistry.createRegistry(8888);
			// 把远程对象注册到RMI注册服务器上,并命名为jmiImpl
			Naming.bind("rmi://localhost:8888/RHello", jmiImpl);
			System.out.println("远程IHello对象绑定成功!");
		} catch (RemoteException e) {
			System.out.println("创建远程对象发生异常!");
			e.printStackTrace();
		} catch (java.rmi.AlreadyBoundException e) {
			System.out.println("发生重复绑定对象异常!");
			e.printStackTrace();
		} catch (MalformedURLException e) {
			System.out.println("发生URL畸形异常!");
			e.printStackTrace();
		}

	}
}

客户端:

package senssic.ejb.imitate;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class JmiDemoClent {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			// 在RMI服务注册表中查找名称为JmiDemoBean的对象,并调用其上的方法
			JmiDemoBean jBean = (JmiDemoBean) Naming
					.lookup("rmi://localhost:8888/RHello");
			System.out.println(jBean.sayHello());
		} catch (NotBoundException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

}

以上jmi的分布式远程调用实例完毕下面我们来看看原理吧

首先我们看下实现序列化的对象通过socket传递的原理:

bean代码:

package senssic.ejb.imitate;

import java.io.Serializable;

//因为是整个序列化,必须实现序列化接口,否则会报错
public class EjbBean implements Serializable {

	private static final long serialVersionUID = 1L;
	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}
服务端:

package senssic.ejb.imitate;

import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class EjbSockSer extends Thread {
	private final EjbBean eBean;
	private final Socket socket;

	public EjbSockSer(EjbBean eBean, Socket socket) {
		this.eBean = eBean;
		this.socket = socket;
	}

	@Override
	public void run() {
		try {

			while (socket != null) {
				ObjectOutputStream oStream = new ObjectOutputStream(
						socket.getOutputStream());
				oStream.writeObject(eBean);
				System.out.println("发给老婆的对象完成。。。");
				oStream.flush();
				oStream.close();
			}
		} catch (Exception e) {
		}
	}

	public static void main(String[] args) throws Exception {
		EjbBean eBean = new EjbBean();
		eBean.setAge(20);
		eBean.setName("senssic");
		ServerSocket serSocket = new ServerSocket(9000);
		System.out.println("今天女朋友生气了,哎,启动女朋友服务!");
		while (true) {
			System.out.println("启动一个爱老婆线程………………");
			Socket socket = serSocket.accept();
			System.out.println("爱老婆服务完成。");
			EjbSockSer eSer = new EjbSockSer(eBean, socket);
			eSer.start();
		}
	}
}
客户端:

package senssic.ejb.imitate;

import java.io.ObjectInputStream;
import java.net.Socket;

public class EjbSockClent {

	public static void main(String[] args) throws Exception {
		Socket socket = new Socket("127.0.0.1", 9000);
		ObjectInputStream inputStream = new ObjectInputStream(
				socket.getInputStream());
		EjbBean eBean = (EjbBean) inputStream.readObject();
		System.out.println("老婆接受到对象---对象姓名:" + eBean.getName() + "对象年龄:"
				+ eBean.getAge());
	}

}
好了,既然是ejb3.0不需要实现序列化接口,那么他是怎么做的呢,rmi是怎么做的呢,我们来看看rmi的原理吧

接口:

package senssic.ejb.imitate;

public interface EjbSenssicBean {
	public String getName() throws Throwable;

	public int getAge() throws Throwable;
}
实现类:

package senssic.ejb.imitate;

public class EjbSenssicBeanImpl implements EjbSenssicBean {
	private final String name;
	private final int age;

	public EjbSenssicBeanImpl(String name, int age) {
		this.name = name;
		this.age = age;

	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public int getAge() {
		return age;
	}

}
服务端:


package senssic.ejb.imitate;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class EjbSenssicSer extends Thread {
	private final EjbSenssicBean eBean;
	private final Socket socket;

	public EjbSenssicSer(EjbSenssicBean eBean, Socket socket) {
		this.eBean = eBean;
		this.socket = socket;
	}

	@Override
	public void run() {
		try {

			while (socket != null) {
				ObjectInputStream iStream = new ObjectInputStream(
						socket.getInputStream());
				String method = (String) iStream.readObject();
				if (method.equals("age")) {
					ObjectOutputStream oStream = new ObjectOutputStream(
							socket.getOutputStream());
					try {
						oStream.writeInt(eBean.getAge());
					} catch (Throwable e) {
						e.printStackTrace();
					}
					oStream.flush();

				}

				if (method.equals("name")) {
					ObjectOutputStream oStream = new ObjectOutputStream(
							socket.getOutputStream());
					try {
						oStream.writeObject(eBean.getName());
					} catch (Throwable e) {
						e.printStackTrace();
					}
					oStream.flush();

				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public static void main(String[] args) throws Exception {
		ServerSocket serSocket = new ServerSocket(9000);
		EjbSenssicBean eBean = new EjbSenssicBeanImpl("senssic", 20);
		while (true) {
			Socket socket = serSocket.accept();
			EjbSenssicSer ejbSenssicSer = new EjbSenssicSer(eBean, socket);
			ejbSenssicSer.start();
		}

	}

}

客户端:

package senssic.ejb.imitate;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class EjbSenssicClent implements EjbSenssicBean {
	private Socket socket;

	public EjbSenssicClent() {
		try {
			socket = new Socket("127.0.0.1", 9000);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public String getName() throws Throwable {

		ObjectOutputStream oStream = new ObjectOutputStream(
				socket.getOutputStream());
		oStream.writeObject("name");
		ObjectInputStream InputStream = new ObjectInputStream(
				socket.getInputStream());
		String name = (String) InputStream.readObject();
		oStream.flush();

		return name;

	}

	@Override
	public int getAge() throws Throwable {

		ObjectOutputStream oStream = new ObjectOutputStream(
				socket.getOutputStream());
		oStream.writeObject("age");
		ObjectInputStream InputStream = new ObjectInputStream(
				socket.getInputStream());
		int age = InputStream.readInt();
		oStream.flush();

		return age;
	}

	public static void main(String[] args) throws Throwable {
		EjbSenssicBean eBean = new EjbSenssicClent();
		System.out.println("远方的名字:" + eBean.getName() + "远方的年龄:"
				+ eBean.getAge());
	}

}
这样我们不用实现序列化接口也能获得远端实例好的对象了





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值