RMI简单实例与Spring集成RMI

     rmi远程方法调用,用于服务器端和客户端之间的会话通信。

      本文以两种方式实现rmi,一种为单独的rmi实例 一种为spring中集成rmi    记录学习的脚步

    1.rmi与jpa的融合

/*
 * 自己编写rmi的话 只需三步 前两步针对服务器端 第三步针对客户端
 * 1.让远程服务实现类继承UnicastRemoteObject  并让远程服务接口继承Remote
 * 2.使用LocateRegistry.createRegistry注册RMI的服务端口 Naming.rebind绑定远程服务对象
 * 3.客户端通过Naming.lookup查找远程服务对象
 * 
 */

远程服务接口类 IStusDAO.java 继承Remote类

package com.undergrowth.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.sql.Timestamp;
import java.util.List;

import com.undergrowth.bean.Stus;

/**
 * Interface for StusDAO.
 * 
 * @author MyEclipse Persistence Tools
 */

public interface IStusDAO extends Remote{
	/**
	 * Perform an initial save of a previously unsaved Stus entity. All
	 * subsequent persist actions of this entity should use the #update()
	 * method. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#persist(Object)
	 * EntityManager#persist} operation.
	 * 
	 * <pre>
	 * EntityManagerHelper.beginTransaction();
	 * IStusDAO.save(entity);
	 * EntityManagerHelper.commit();
	 * </pre>
	 * 
	 * @param entity
	 *            Stus entity to persist
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void save(Stus entity) throws RemoteException;

	/**
	 * Delete a persistent Stus entity. This operation must be performed within
	 * the a database transaction context for the entity's data to be
	 * permanently deleted from the persistence store, i.e., database. This
	 * method uses the {@link javax.persistence.EntityManager#remove(Object)
	 * EntityManager#delete} operation.
	 * 
	 * <pre>
	 * EntityManagerHelper.beginTransaction();
	 * IStusDAO.delete(entity);
	 * EntityManagerHelper.commit();
	 * entity = null;
	 * </pre>
	 * 
	 * @param entity
	 *            Stus entity to delete
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void delete(Stus entity) throws RemoteException;

	/**
	 * Persist a previously saved Stus entity and return it or a copy of it to
	 * the sender. A copy of the Stus entity parameter is returned when the JPA
	 * persistence mechanism has not previously been tracking the updated
	 * entity. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#merge(Object) EntityManager#merge}
	 * operation.
	 * 
	 * <pre>
	 * EntityManagerHelper.beginTransaction();
	 * entity = IStusDAO.update(entity);
	 * EntityManagerHelper.commit();
	 * </pre>
	 * 
	 * @param entity
	 *            Stus entity to update
	 * @return Stus the persisted Stus entity instance, may not be the same
	 * @throws RuntimeException
	 *             if the operation fails
	 */
	public Stus update(Stus entity) throws RemoteException;

	public Stus findById(String id) throws RemoteException;

	/**
	 * Find all Stus entities with a specific property value.
	 * 
	 * @param propertyName
	 *            the name of the Stus property to query
	 * @param value
	 *            the property value to match
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            count of results to return.
	 * @return List<Stus> found by query
	 */
	public List<Stus> findByProperty(String propertyName, Object value,
			int... rowStartIdxAndCount) throws RemoteException;

	public List<Stus> findByStuName(Object stuName, int... rowStartIdxAndCount) throws RemoteException;

	public List<Stus> findByStuAge(Object stuAge, int... rowStartIdxAndCount) throws RemoteException;

	/**
	 * Find all Stus entities.
	 * 
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            count of results to return.
	 * @return List<Stus> all Stus entities
	 */
	public List<Stus> findAll(int... rowStartIdxAndCount) throws RemoteException;
}

远程服务实现类 StusDAO.java 继承UnicastRemoteObject

package com.undergrowth.rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Timestamp;
import java.util.List;
import java.util.logging.Level;
import javax.persistence.EntityManager;
import javax.persistence.Query;

import com.undergrowth.bean.EntityManagerHelper;
import com.undergrowth.bean.Stus;

/**
 * A data access object (DAO) providing persistence and search support for Stus
 * entities. Transaction control of the save(), update() and delete() operations
 * must be handled externally by senders of these methods or must be manually
 * added to each of these methods for data to be persisted to the JPA datastore.
 * 
 * @see com.undergrowth.bean.Stus
 * @author MyEclipse Persistence Tools
 */
public class StusDAO extends UnicastRemoteObject implements IStusDAO {
	
	public StusDAO() throws RemoteException {
		super();
		// TODO Auto-generated constructor stub
	}

	// property constants
	public static final String STU_NAME = "stuName";
	public static final String STU_AGE = "stuAge";

	private EntityManager getEntityManager() {
		return EntityManagerHelper.getEntityManager();
	}

	/**
	 * Perform an initial save of a previously unsaved Stus entity. All
	 * subsequent persist actions of this entity should use the #update()
	 * method. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#persist(Object)
	 * EntityManager#persist} operation.
	 * 
	 * <pre>
	 * EntityManagerHelper.beginTransaction();
	 * StusDAO.save(entity);
	 * EntityManagerHelper.commit();
	 * </pre>
	 * 
	 * @param entity
	 *            Stus entity to persist
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void save(Stus entity) throws RemoteException{
		EntityManagerHelper.log("saving Stus instance", Level.INFO, null);
		try {
			getEntityManager().persist(entity);
			EntityManagerHelper.log("save successful", Level.INFO, null);
		} catch (RuntimeException re) {
			EntityManagerHelper.log("save failed", Level.SEVERE, re);
			throw re;
		}
	}

	/**
	 * Delete a persistent Stus entity. This operation must be performed within
	 * the a database transaction context for the entity's data to be
	 * permanently deleted from the persistence store, i.e., database. This
	 * method uses the {@link javax.persistence.EntityManager#remove(Object)
	 * EntityManager#delete} operation.
	 * 
	 * <pre>
	 * EntityManagerHelper.beginTransaction();
	 * StusDAO.delete(entity);
	 * EntityManagerHelper.commit();
	 * entity = null;
	 * </pre>
	 * 
	 * @param entity
	 *            Stus entity to delete
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void delete(Stus entity) throws RemoteException{
		EntityManagerHelper.log("deleting Stus instance", Level.INFO, null);
		try {
			entity = getEntityManager().getReference(Stus.class,
					entity.getStuId());
			getEntityManager().remove(entity);
			EntityManagerHelper.log("delete successful", Level.INFO, null);
		} catch (RuntimeException re) {
			EntityManagerHelper.log("delete failed", Level.SEVERE, re);
			throw re;
		}
	}

	/**
	 * Persist a previously saved Stus entity and return it or a copy of it to
	 * the sender. A copy of the Stus entity parameter is returned when the JPA
	 * persistence mechanism has not previously been tracking the updated
	 * entity. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#merge(Object) EntityManager#merge}
	 * operation.
	 * 
	 * <pre>
	 * EntityManagerHelper.beginTransaction();
	 * entity = StusDAO.update(entity);
	 * EntityManagerHelper.commit();
	 * </pre>
	 * 
	 * @param entity
	 *            Stus entity to update
	 * @return Stus the persisted Stus entity instance, may not be the same
	 * @throws RuntimeException
	 *             if the operation fails
	 */
	public Stus update(Stus entity) throws RemoteException{
		EntityManagerHelper.log("updating Stus instance", Level.INFO, null);
		try {
			Stus result = getEntityManager().merge(entity);
			EntityManagerHelper.log("update successful", Level.INFO, null);
			return result;
		} catch (RuntimeException re) {
			EntityManagerHelper.log("update failed", Level.SEVERE, re);
			throw re;
		}
	}

	public Stus findById(String id) throws RemoteException{
		EntityManagerHelper.log("finding Stus instance with id: " + id,
				Level.INFO, null);
		try {
			Stus instance = getEntityManager().find(Stus.class, id);
			return instance;
		} catch (RuntimeException re) {
			EntityManagerHelper.log("find failed", Level.SEVERE, re);
			throw re;
		}
	}

	/**
	 * Find all Stus entities with a specific property value.
	 * 
	 * @param propertyName
	 *            the name of the Stus property to query
	 * @param value
	 *            the property value to match
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            number of results to return.
	 * @return List<Stus> found by query
	 */
	@SuppressWarnings("unchecked")
	public List<Stus> findByProperty(String propertyName, final Object value,
			final int... rowStartIdxAndCount) throws RemoteException{
		EntityManagerHelper.log("finding Stus instance with property: "
				+ propertyName + ", value: " + value, Level.INFO, null);
		try {
			final String queryString = "select model from Stus model where model."
					+ propertyName + "= :propertyValue";
			Query query = getEntityManager().createQuery(queryString);
			query.setParameter("propertyValue", value);
			if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {
				int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
				if (rowStartIdx > 0) {
					query.setFirstResult(rowStartIdx);
				}

				if (rowStartIdxAndCount.length > 1) {
					int rowCount = Math.max(0, rowStartIdxAndCount[1]);
					if (rowCount > 0) {
						query.setMaxResults(rowCount);
					}
				}
			}
			return query.getResultList();
		} catch (RuntimeException re) {
			EntityManagerHelper.log("find by property name failed",
					Level.SEVERE, re);
			throw re;
		}
	}

	public List<Stus> findByStuName(Object stuName, int... rowStartIdxAndCount) throws RemoteException{
		return findByProperty(STU_NAME, stuName, rowStartIdxAndCount);
	}

	public List<Stus> findByStuAge(Object stuAge, int... rowStartIdxAndCount) throws RemoteException{
		return findByProperty(STU_AGE, stuAge, rowStartIdxAndCount);
	}

	/**
	 * Find all Stus entities.
	 * 
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            count of results to return.
	 * @return List<Stus> all Stus entities
	 */
	@SuppressWarnings("unchecked")
	public List<Stus> findAll(final int... rowStartIdxAndCount) throws RemoteException{
		EntityManagerHelper.log("finding all Stus instances", Level.INFO, null);
		try {
			final String queryString = "select model from Stus model";
			Query query = getEntityManager().createQuery(queryString);
			if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {
				int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
				if (rowStartIdx > 0) {
					query.setFirstResult(rowStartIdx);
				}

				if (rowStartIdxAndCount.length > 1) {
					int rowCount = Math.max(0, rowStartIdxAndCount[1]);
					if (rowCount > 0) {
						query.setMaxResults(rowCount);
					}
				}
			}
			return query.getResultList();
		} catch (RuntimeException re) {
			EntityManagerHelper.log("find all failed", Level.SEVERE, re);
			throw re;
		}
	}

}

注册远程服务对象 RmiServer.java

package com.undergrowth.junit;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

import com.undergrowth.rmi.IStusDAO;
import com.undergrowth.rmi.StusDAO;

/*
 * 自己编写rmi的话 只需三步 前两步针对服务器端 第三步针对客户端
 * 1.让远程服务实现类继承UnicastRemoteObject  并让远程服务接口继承Remote
 * 2.使用LocateRegistry.createRegistry注册RMI的服务端口 Naming.rebind绑定远程服务对象
 * 3.客户端通过Naming.lookup查找远程服务对象
 * 
 */

public class RmiServer {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			IStusDAO istusDAO=new StusDAO();
			//System.setProperty("java.rmi.server.hostname", "192.168.38.172");
			//创建访问rmi的远程端口
			//启动rmiregister程序
			//Runtime.getRuntime().exec("rmiregistry 4567");
			LocateRegistry.createRegistry(4567);
			//注册远程服务对象
			Naming.rebind("rmi://192.168.38.172:4567/IStusDAO", istusDAO);
			System.out.println("注册远程服务对象成功");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

在cmd下查看rmi绑定的端口



客户端测试 RmiClient.java

package com.undergrowth.junit;

import java.rmi.Naming;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;

import com.undergrowth.bean.Stus;
import com.undergrowth.rmi.IStusDAO;

public class RmiClient {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			IStusDAO iStusDAO=(IStusDAO) Naming.lookup("rmi://192.168.38.172:4567/IStusDAO");
			List<Stus> listStus=iStusDAO.findAll();
			for (Stus stus : listStus) {
				System.out.println(stus);
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

客户端输出

Stus [stuId=014ED6D01D9B4C6E882E3624032FA9CD, stuName=sz, stuAge=21.0, stuBirthday=2014-04-19 15:07:33.0]
Stus [stuId=946E460A4FA14D8496EF601E754FD314, stuName=gz, stuAge=20.0, stuBirthday=2014-04-19 15:07:33.0]

2.spring集成rmi和jpa

/*
 * spring支持的rmi很简单  
 * 不用服务接口继承Remote
 * 不用服务实现类继承UnicastRemoteObject
 * 也不用我们自己注册rmi的远程服务实现类
 * 
 * 服务器端 你需要做的仅仅是 写好你需要提供远程服务的实现类
 * 然后将其交给RmiServiceExporter类 RmiServiceExporter会将实现类发布为RMI服务
 * 
 * 客户端 也很简单
 * 只需要使用RmiProxyFactoryBean从服务器端的URL从获取服务对象  并进行封装给你定义的id
 * 然后从spring容器中获取RmiProxyFactoryBean封装的id即可
 * 
 * 此测试代码中 服务器和客户端都在一个项目中 也可换成多个项目 在不同的电脑中
 * 只需要在服务器的RmiServiceExporter中加入 p:registryHost="ip地址" 即可
 * 客户端将localhost换成ip地址即可
 */


spring的配置文件 如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
	xmlns:tx="http://www.springframework.org/schema/tx">

    <!-- spring 的jpa的事务管理  -->
	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="SpringRmiAndJpa" />
	</bean>
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager" />
	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
	</bean>
	<bean
		class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor">
	</bean>
	
	<bean id="IStusDAO" class="com.undergrowth.bean.StusDAO"></bean>
	
	<!-- 使用RmiServiceExporter将IStusDAO的对象导出为RMI服务对象 -->
	<bean class="org.springframework.remoting.rmi.RmiServiceExporter" 
	p:service-ref="IStusDAO"
	p:serviceName="IStusDAO"
	p:registryPort="1199"
	p:serviceInterface="com.undergrowth.bean.IStusDAO"
	/>
	
	<!-- 使用RmiProxyFactoryBean从远程服务处获取服务的对象 并将其封装成stusDao对象 -->
	<bean id="stusDao" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"
		p:serviceUrl="rmi://localhost:1199/IStusDAO"
		p:serviceInterface="com.undergrowth.bean.IStusDAO"
	/>
	
</beans>

服务接口实现类 StusDAO.java

package com.undergrowth.bean;

import java.sql.Timestamp;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
 * A data access object (DAO) providing persistence and search support for Stus
 * entities. Transaction control of the save(), update() and delete() operations
 * can directly support Spring container-managed transactions or they can be
 * augmented to handle user-managed Spring transactions. Each of these methods
 * provides additional information for how to configure it for the desired type
 * of transaction control.
 * 
 * @see com.undergrowth.bean.Stus
 * @author MyEclipse Persistence Tools
 */
@Transactional
@Repository
public class StusDAO implements IStusDAO {
	private static final Log logger = LogFactory.getLog(StusDAO.class);
	// property constants
	public static final String STU_NAME = "stuName";
	public static final String STU_AGE = "stuAge";

	private EntityManager entityManager;

	@PersistenceContext
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	private EntityManager getEntityManager() {
		return entityManager;
	}

	/**
	 * Perform an initial save of a previously unsaved Stus entity. All
	 * subsequent persist actions of this entity should use the #update()
	 * method. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#persist(Object)
	 * EntityManager#persist} operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * StusDAO.save(entity);
	 * txManager.commit(txn);
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Stus entity to persist
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void save(Stus entity) {
		logger.info("saving Stus instance");
		try {
			getEntityManager().persist(entity);
			logger.info("save successful");
		} catch (RuntimeException re) {
			logger.error("save failed", re);
			throw re;
		}
	}

	/**
	 * Delete a persistent Stus entity. This operation must be performed within
	 * the a database transaction context for the entity's data to be
	 * permanently deleted from the persistence store, i.e., database. This
	 * method uses the {@link javax.persistence.EntityManager#remove(Object)
	 * EntityManager#delete} operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * StusDAO.delete(entity);
	 * txManager.commit(txn);
	 * entity = null;
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Stus entity to delete
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void delete(Stus entity) {
		logger.info("deleting Stus instance");
		try {
			entity = getEntityManager().getReference(Stus.class,
					entity.getStuId());
			getEntityManager().remove(entity);
			logger.info("delete successful");
		} catch (RuntimeException re) {
			logger.error("delete failed", re);
			throw re;
		}
	}

	/**
	 * Persist a previously saved Stus entity and return it or a copy of it to
	 * the sender. A copy of the Stus entity parameter is returned when the JPA
	 * persistence mechanism has not previously been tracking the updated
	 * entity. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#merge(Object) EntityManager#merge}
	 * operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * entity = StusDAO.update(entity);
	 * txManager.commit(txn);
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Stus entity to update
	 * @return Stus the persisted Stus entity instance, may not be the same
	 * @throws RuntimeException
	 *             if the operation fails
	 */
	public Stus update(Stus entity) {
		logger.info("updating Stus instance");
		try {
			Stus result = getEntityManager().merge(entity);
			logger.info("update successful");
			return result;
		} catch (RuntimeException re) {
			logger.error("update failed", re);
			throw re;
		}
	}

	public Stus findById(String id) {
		logger.info("finding Stus instance with id: " + id);
		try {
			Stus instance = getEntityManager().find(Stus.class, id);
			return instance;
		} catch (RuntimeException re) {
			logger.error("find failed", re);
			throw re;
		}
	}

	/**
	 * Find all Stus entities with a specific property value.
	 * 
	 * @param propertyName
	 *            the name of the Stus property to query
	 * @param value
	 *            the property value to match
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            number of results to return.
	 * @return List<Stus> found by query
	 */
	@SuppressWarnings("unchecked")
	public List<Stus> findByProperty(String propertyName, final Object value,
			final int... rowStartIdxAndCount) {
		logger.info("finding Stus instance with property: " + propertyName
				+ ", value: " + value);
		try {
			final String queryString = "select model from Stus model where model."
					+ propertyName + "= :propertyValue";
			Query query = getEntityManager().createQuery(queryString);
			query.setParameter("propertyValue", value);
			if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {
				int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
				if (rowStartIdx > 0) {
					query.setFirstResult(rowStartIdx);
				}

				if (rowStartIdxAndCount.length > 1) {
					int rowCount = Math.max(0, rowStartIdxAndCount[1]);
					if (rowCount > 0) {
						query.setMaxResults(rowCount);
					}
				}
			}
			return query.getResultList();
		} catch (RuntimeException re) {
			logger.error("find by property name failed", re);
			throw re;
		}
	}

	public List<Stus> findByStuName(Object stuName, int... rowStartIdxAndCount) {
		return findByProperty(STU_NAME, stuName, rowStartIdxAndCount);
	}

	public List<Stus> findByStuAge(Object stuAge, int... rowStartIdxAndCount) {
		return findByProperty(STU_AGE, stuAge, rowStartIdxAndCount);
	}

	/**
	 * Find all Stus entities.
	 * 
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            count of results to return.
	 * @return List<Stus> all Stus entities
	 */
	@SuppressWarnings("unchecked")
	public List<Stus> findAll(final int... rowStartIdxAndCount) {
		logger.info("finding all Stus instances");
		try {
			final String queryString = "select model from Stus model";
			Query query = getEntityManager().createQuery(queryString);
			if (rowStartIdxAndCount != null && rowStartIdxAndCount.length > 0) {
				int rowStartIdx = Math.max(0, rowStartIdxAndCount[0]);
				if (rowStartIdx > 0) {
					query.setFirstResult(rowStartIdx);
				}

				if (rowStartIdxAndCount.length > 1) {
					int rowCount = Math.max(0, rowStartIdxAndCount[1]);
					if (rowCount > 0) {
						query.setMaxResults(rowCount);
					}
				}
			}
			return query.getResultList();
		} catch (RuntimeException re) {
			logger.error("find all failed", re);
			throw re;
		}
	}

	public static IStusDAO getFromApplicationContext(ApplicationContext ctx) {
		return (IStusDAO) ctx.getBean("StusDAO");
	}
}

上面的 @Transactional 用于spring的jpa的事务管理  


服务接口 IStusDAO.java

package com.undergrowth.bean;

import java.sql.Timestamp;
import java.util.List;

/**
 * Interface for StusDAO.
 * 
 * @author MyEclipse Persistence Tools
 */

public interface IStusDAO {
	/**
	 * Perform an initial save of a previously unsaved Stus entity. All
	 * subsequent persist actions of this entity should use the #update()
	 * method. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#persist(Object)
	 * EntityManager#persist} operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * IStusDAO.save(entity);
	 * txManager.commit(txn);
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Stus entity to persist
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void save(Stus entity);

	/**
	 * Delete a persistent Stus entity. This operation must be performed within
	 * the a database transaction context for the entity's data to be
	 * permanently deleted from the persistence store, i.e., database. This
	 * method uses the {@link javax.persistence.EntityManager#remove(Object)
	 * EntityManager#delete} operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * IStusDAO.delete(entity);
	 * txManager.commit(txn);
	 * entity = null;
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Stus entity to delete
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public void delete(Stus entity);

	/**
	 * Persist a previously saved Stus entity and return it or a copy of it to
	 * the sender. A copy of the Stus entity parameter is returned when the JPA
	 * persistence mechanism has not previously been tracking the updated
	 * entity. This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#merge(Object) EntityManager#merge}
	 * operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * entity = IStusDAO.update(entity);
	 * txManager.commit(txn);
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Stus entity to update
	 * @return Stus the persisted Stus entity instance, may not be the same
	 * @throws RuntimeException
	 *             if the operation fails
	 */
	public Stus update(Stus entity);

	public Stus findById(String id);

	/**
	 * Find all Stus entities with a specific property value.
	 * 
	 * @param propertyName
	 *            the name of the Stus property to query
	 * @param value
	 *            the property value to match
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            count of results to return.
	 * @return List<Stus> found by query
	 */
	public List<Stus> findByProperty(String propertyName, Object value,
			int... rowStartIdxAndCount);

	public List<Stus> findByStuName(Object stuName, int... rowStartIdxAndCount);

	public List<Stus> findByStuAge(Object stuAge, int... rowStartIdxAndCount);

	/**
	 * Find all Stus entities.
	 * 
	 * @param rowStartIdxAndCount
	 *            Optional int varargs. rowStartIdxAndCount[0] specifies the the
	 *            row index in the query result-set to begin collecting the
	 *            results. rowStartIdxAndCount[1] specifies the the maximum
	 *            count of results to return.
	 * @return List<Stus> all Stus entities
	 */
	public List<Stus> findAll(int... rowStartIdxAndCount);
}

客户端实现 SpringRmiClient.java

package com.undergrowth.junit;

import static org.junit.Assert.*;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.undergrowth.bean.IStusDAO;
import com.undergrowth.bean.Stus;

/*
 * spring支持的rmi很简单  
 * 不用服务接口继承Remote
 * 不用服务实现类继承UnicastRemoteObject
 * 也不用我们自己注册rmi的远程服务实现类
 * 
 * 服务器端 你需要做的仅仅是 写好你需要提供远程服务的实现类
 * 然后将其交给RmiServiceExporter类 RmiServiceExporter会将实现类发布为RMI服务
 * 
 * 客户端 也很简单
 * 只需要使用RmiProxyFactoryBean从服务器端的URL从获取服务对象  并进行封装给你定义的id
 * 然后从spring容器中获取RmiProxyFactoryBean封装的id即可
 * 
 * 此测试代码中 服务器和客户端都在一个项目中 也可换成多个项目 在不同的电脑中
 * 只需要在服务器的RmiServiceExporter中加入 p:registryHost="ip地址" 即可
 * 客户端将localhost换成ip地址即可
 */
public class SpringRmiClient {

	@Test
	public void testRmiClient() {
		ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
		//获取封装的远程服务对象
		IStusDAO iStusDAO=(IStusDAO) ac.getBean("stusDao");
		//调用远程服务对象的方法 返回列表结果
		List<Stus> list=iStusDAO.findAll();
		for (Stus stus : list) {
			System.out.println(stus);
		}
		//添加
		Stus stus=new Stus(UUID.randomUUID().toString(), "spring rmi客户端", 78.9, new Timestamp(Calendar.getInstance().getTimeInMillis()));
		iStusDAO.save(stus);
		
		list=iStusDAO.findAll();
		for (Stus stus2 : list) {
			System.out.println(stus2);
		}
		
		
		//如果不加下面的while语句  那么 执行完此测试方法后 在cmd中 就看不到rmi的绑定端口信息 
		//因为spring在测试完成后 会清理相关的rmi信息
		//while(true){}
	}

}

控制台输出

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[EL Info]: 2014-05-03 12:44:50.747--ServerSession(17038506)--EclipseLink, version: Eclipse Persistence Services - 2.5.0.v20130507-3faac2b
[EL Info]: connection: 2014-05-03 12:44:51.655--ServerSession(17038506)--file:/D:/learnsoftware/java/AndroidDevelop/myeclipse_2013_code/SpringRmiAndJpa/bin/_SpringRmiAndJpa login successful
Stus [stuId=014ED6D01D9B4C6E882E3624032FA9CD, stuName=sz, stuAge=21.0, stuBirthday=2014-04-19 15:07:33.0]
Stus [stuId=946E460A4FA14D8496EF601E754FD314, stuName=gz, stuAge=20.0, stuBirthday=2014-04-19 15:07:33.0]
Stus [stuId=014ED6D01D9B4C6E882E3624032FA9CD, stuName=sz, stuAge=21.0, stuBirthday=2014-04-19 15:07:33.0]
Stus [stuId=946E460A4FA14D8496EF601E754FD314, stuName=gz, stuAge=20.0, stuBirthday=2014-04-19 15:07:33.0]
Stus [stuId=96d4f969-6d0a-4f6d-940f-e97b73080314, stuName=spring rmi客户端, stuAge=78.9, stuBirthday=2014-05-03 12:44:52.591]



对比以上两种方式 会发现spring的rmi比自己写的rmi要简单、方便的多 不过前提是你对spring要有一定的了解


其实使用自定义的rmi方式时 遇到了很多我称之为诡异的现象 也记录一下吧

其实当我写好远程服务接口和远程服务实现类时 我尝试着使用junit类进行测试 如下 

package com.undergrowth.junit;

import static org.junit.Assert.*;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.List;

import org.junit.Test;

import com.undergrowth.bean.Stus;
import com.undergrowth.rmi.IStusDAO;
import com.undergrowth.rmi.StusDAO;

public class RmiJunit {

	@Test
	public void testServer() {
		
		try {
			IStusDAO istusDAO=new StusDAO();
			//System.setProperty("java.rmi.server.hostname", "192.168.38.172");
			//创建访问rmi的远程端口
			//启动rmiregister程序
			//Runtime.getRuntime().exec("rmiregistry 4567");
			LocateRegistry.createRegistry(4567);
			//注册远程服务对象
			Naming.rebind("rmi://192.168.38.172:4567/IStusDAO", istusDAO);
			System.out.println("注册远程服务对象成功");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	@Test
	public void testClient() {
		
		try {
			IStusDAO iStusDAO=(IStusDAO) Naming.lookup("rmi://192.168.38.172:4567/IStusDAO");
			/*List<Stus> listStus=iStusDAO.findAll();
			for (Stus stus : listStus) {
				System.out.println(stus);
			}*/
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	@Test
	public void testCon(){
		IStusDAO iStusDAO;
		try {
			iStusDAO = new StusDAO();
			List<Stus> listStus=iStusDAO.findAll();
			for (Stus stus : listStus) {
				System.out.println(stus);
			}
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}


先运行testServer没有问题  控制台打印出 

注册远程服务对象成功
即表示服务器端注册rmi服务是没有问题的 看起来是这样 是么?

其实不是 接着看 然后运行testClient 发现报错了 

java.rmi.ConnectException: Connection refused to host: 192.168.38.172; nested exception is: 
	java.net.ConnectException: Connection refused: connect
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:601)
	at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
	at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
	at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
	at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
	at java.rmi.Naming.lookup(Naming.java:84)
	at com.undergrowth.junit.RmiJunit.testClient(RmiJunit.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.net.ConnectException: Connection refused: connect
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
	at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
	at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
	at java.net.Socket.connect(Socket.java:529)
	at java.net.Socket.connect(Socket.java:478)
	at java.net.Socket.<init>(Socket.java:375)
	at java.net.Socket.<init>(Socket.java:189)
	at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
	at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
	at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
	... 29 more

上网一搜 好多 经典的错误 但是我都排查了 说ip错误的 不是  说服务器和客户端的rmi的url要一致 也不是  

很明显  是客户端无法连接上服务器的rmi端口 于是 


发现cmd下面居然没有 4567的端口监听

这让我好郁闷 接着寻寻觅觅 还是没找到原因  将testServer和testClient换成两个main函数后  发现就正常了  好吧 我发现我找到原因了 

在testServer里面加上一句 如下

@Test
	public void testServer() {
		
		try {
			IStusDAO istusDAO=new StusDAO();
			//System.setProperty("java.rmi.server.hostname", "192.168.38.172");
			//创建访问rmi的远程端口
			//启动rmiregister程序
			//Runtime.getRuntime().exec("rmiregistry 4567");
			LocateRegistry.createRegistry(4567);
			//注册远程服务对象
			Naming.rebind("rmi://192.168.38.172:4567/IStusDAO", istusDAO);
			System.out.println("注册远程服务对象成功");
			while(true){}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

因为在与testServer运行完后 如果没有加while(true){} 这句的话  注册的rmi这个进程就关掉了  进程都关了 rmi的端口监听也就不存在了 客户端还怎么连的上呢 郁闷死了 不过 好歹解决了


当然 如果使用  

Runtime.getRuntime().exec("rmiregistry 4567");
的话 则会在后台创建一个rmiregistry的进程 这样 rmi的服务就不依赖于当前的进程了  但是  在Naming.rebind的时候 则会报错 如下

@Test
	public void testServer() {
		
		try {
			IStusDAO istusDAO=new StusDAO();
			//System.setProperty("java.rmi.server.hostname", "192.168.38.172");
			//创建访问rmi的远程端口
			//启动rmiregister程序
			Runtime.getRuntime().exec("rmiregistry 5678");
			//LocateRegistry.createRegistry(5678);
			//注册远程服务对象
			Naming.rebind("rmi://192.168.38.172:5678/IStusDAO", istusDAO);
			System.out.println("注册远程服务对象成功");
			//while(true){}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

错误

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
	java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: com.undergrowth.rmi.IStusDAO
	at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:400)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:248)
	at sun.rmi.transport.Transport$1.run(Transport.java:159)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)
	at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
	at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
	at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359)
	at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
	at java.rmi.Naming.rebind(Naming.java:160)
	at com.undergrowth.junit.RmiJunit.testServer(RmiJunit.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: com.undergrowth.rmi.IStusDAO
	at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
	at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:390)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:248)
	at sun.rmi.transport.Transport$1.run(Transport.java:159)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassNotFoundException: com.undergrowth.rmi.IStusDAO
	at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:249)
	at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:709)
	at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:653)
	at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:590)
	at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:628)
	at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294)
	at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:238)
	at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1528)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1490)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1729)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1326)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
	... 12 more

原因在于  使用rmiregistry的进程的时候  在注册istusDAO对象的时候  使用的是相对路径查找istusDAO的类 而rmiregistry进程根本不知道istusDAO的类在哪里 

有解决办法 即 进入到istusDAO的所在目录 在运行测试方法 即可

原文地址:https://www.cnblogs.com/liangxinzhi/p/4275575.html