关于Java/RMI/JBoss/EJB/WebService/JMS的使用

写一篇巨杂的流水记录下对j2ee的某些技术的浏览。


webservice是为跨平台设计的通信语言,不过HelloWorld而言,C#要做得比java要好很多很多!

第一方面:C#提供WebService,C#或Java调用。

C#新建WebService的步骤如下:

  1. 新建Asp.net Web工程。
  2. 添加文件=>webservice,输入文件名。
  3. 右键文件=>在浏览器中预览就可以看到webservice,点击invoke可以调用它。
  4. Winlin.asmx的代码如下:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    
    namespace MyWebService
    {
        /// <summary>
        /// Summary description for Winlin
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
        // [System.Web.Script.Services.ScriptService]
        public class Winlin : System.Web.Services.WebService
        {
            [WebMethod]
            public string HelloWorld()
            {
                return "C# WebService: Hello World!";
            }
        }
    }

C#使用WebService也灰常简单:

  1. 添加Service引用
  2. 填入刚刚预览的地址:http://localhost:59851/Winlin.asmx?WSDL
  3. 输入引用的命名空间(将该webservice装入该命名空间,例如csharp)
  4. 直接调用类就可以了:
    using System;
    
    namespace WebServiceClient
    {
        class Program
        {
            static void Main(string[] args)
            {
                csharp.WinlinSoapClient client = new csharp.WinlinSoapClient();
                Console.WriteLine(client.HelloWorld());
            }
        }
    }

而Java搞清楚了其实也很简单,不过对于初学者就得翻很多资料,找很多例子,IDE并不能搞好这个事情。

Java调用C#生成的webservice的方法如下:

  1. 新建Java工程。例如MyWSClient。
  2. 运行cmd.exe,进入工程目录,例如:
    cd d:\tvie\lab\java\wsClient\src
  3. 生成调用webService的stub:
    wsimport -p org.tempuri -keep http://localhost:59851/Winlin.asmx?WSDL
  4. 注:不要引用jboss的jar,否则会报错:
    java.lang.ClassNotFoundException: com.sun.xml.messaging.saaj.soap.AttachmentPartImpl
  5. 可以看到生成了一堆的文件。
  6. 调用:
    import org.tempuri.*;
    
    public class CSharpWSInvoke {
        public static void main(String[] args){
            Winlin winlin = new Winlin();
            WinlinSoap soap = winlin.getWinlinSoap();
            System.out.println(soap.helloWorld());
        }
    }
Java提供WebService有两种方法,直接用Endpoint.publish(新建WebServer),或者用EJB的stateless session bean发布。

第二方面:Java直接提供WebService,C#或Java调用。

Java直接提供WebService的方法如下:

  1. 新建Java工程,例如MyWSClient。
  2. 必须新建packet,不能使用默认的packet。例如cn.winlin。
  3. 新建Class,内容如下:
    package cn.winlin;
    
    import javax.jws.WebMethod;
    import javax.jws.WebService;
    import javax.xml.ws.Endpoint;
    
    @WebService
    public class Hello {
        @WebMethod
        public String hello(String name){
            return "Hello, "+name;
        }
        public static void main(String[] args){
            Hello hello = new Hello();
            Endpoint.publish("http://localhost:8081/hello", hello);
            System.out.println("webservice published!");
        }
    }
  4. 然后打开cmd.exe,进入目录:
    cd D:\tvie\lab\java\wsServer\src
  5. 生成webservice:
    apt -d build cn\winlin\Hello.java
  6. 启动webservice:
    cd build
    java cn.winlin.Hello
  7. 可以看到service启动成功:
    http://localhost:8081/hello?wsdl

调用方法同上。

Java的调用方法:

  1. 新建工程,例如MyWSClient。
  2. 打开cmd.exe,进入目录:
    cd d:\tvie\lab\java\wsClient\src
    wsimport -p cn.winlin -keep http://localhost:8081/hello?wsdl
  3. 然后新建Java类调用:
    import cn.winlin.*;
    
    public class JavaWSInvoke {
        public static void main(String[] args){
            HelloService service = new HelloService();
            Hello hello = service.getHelloPort();
            System.out.println(hello.hello("winlin"));
        }
    }

第三方面:Java使用EJB SLSB提供webservice

EJB的Stateless Session Bean能以简单方式提供webservice。方法如下:

  1. 新建EJB工程。
  2. 添加无状态Session Bean。提供remote接口。
  3. Remote接口定义如下:
    package com.winlin;
    import javax.ejb.Remote;
    
    @Remote
    public interface MyWebServiceRemote {
    }
  4. 在实现类中添加标记即可:
    package com.winlin;
    
    import javax.ejb.Stateless;
    import javax.jws.WebMethod;
    import javax.jws.WebService;
    
    @Stateless
    @WebService
    public class MyWeb implements MyWebServiceRemote {
        public MyWeb() {
        }
        
        @WebMethod
        public String sayHello()
        {
            return "WebService: it's me!";
        }
    
        @WebMethod
        public String sayName(String name)
        {
            System.out.println("WS: sayName(\""+name+"\")invoked!");
            return "WebService: it's me "+name;
        }
    }
  5. 直接发布到容器,例如jboss。
  6. 调用方法同上。

以java调用为例,方法如下:

  1. 生成stub,调用wsimport命令,同上。
  2. 调用:
    import com.winlin.*;
    
    public class MyWebInvoker
    {
        public static void main(String[] args) {
            MyWebService web = new MyWebService();
            MyWeb me = web.getMyWebPort();
            System.out.println(me.sayHello());
        }
    }
而C#的调用会麻烦一些:
  1. 添加webservice引用后,调用如下:
    using System;
    
    namespace WebServiceClient
    {
        class Program
        {
            static void Main(string[] args)
            {
                ejb.MyWebClient ejbclient = new ejb.MyWebClient();
                ejb.sayHelloResponse ejbres = ejbclient.sayHello(new ejb.sayHello());
                Console.WriteLine(ejbres.@return);
            }
        }
    }
关键是用wsimport生成stub。


第四方面:提供WebService的问题:Jboss5不兼容jdk1.6

JBOSS 5使用jdk1.6时会有ws不兼容的情况。

若SLSB暴露webservice报错:

java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage

则执行如下命令:

cp client/jbossws-native-jaxrpc.jar lib/endorsed/
cp client/jbossws-native-jaxws.jar lib/endorsed/
cp client/jbossws-native-jaxws-ext.jar lib/endorsed/
cp client/jbossws-native-saaj.jar lib/endorsed/ 

第五方面:JBoss的启动参数和WebService的地址

webservice生成的地址默认是127.0.0.1,可以在jboss启动时指定为本机ip:

./run.sh -b 10.12.12.101


第六方面:使用Mysql数据库,对外提供WebService调用

使用EJB数据库的例子:
  1. 拷贝mysql-ds.xml到deploy,里面包含数据库的数据源。内容如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <datasources>
        <local-tx-datasource>
        <jndi-name>MySqlDS_EJB</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/mysql_ejb</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>tvie</user-name>
        <password>tvie</password>
        <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
        <metadata>
            <type-mapping>mySQL</type-mapping>
        </metadata>
        </local-tx-datasource>
    </datasources>
  2. 创建数据库,进入mysql后执行如下sq语句:
    drop DATABASE IF EXISTS `mysql_ejb`;
    create DATABASE mysql_ejb;
    use mysql_ejb;
    DROP TABLE IF EXISTS `Project`;
    CREATE TABLE `Project` (
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'the id of project',
    `source` varchar(2000) DEFAULT NULL COMMENT 'the friendly project name',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
  3. 在ejbModule\META-INF目录,新建文件persistence.xml,内容如下(红色字体和mysql-ds.xml中保持一致):
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
        version="1.0">
        <persistence-unit name="mysql_ejb">
            <jta-data-source>java:/MySqlDS_EJB</jta-data-source>
            <properties>
                <property name="hibernate.hbm2ddl.auto" value="none" />
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
            </properties>
        </persistence-unit>
    </persistence>
  4. 新建数据实体EntityBean,映射到表:
    package com.winlin.db;
    
    import java.io.Serializable;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @Table(name = "Project")
    @SuppressWarnings("serial")
    public class Project implements Serializable
    {
        private Integer id;
        private String source;
        
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        public Integer getId(){
            return this.id;
        }
        
        public void setId(Integer id){
            this.id = id;
        }
        
        public String getSource(){
            return this.source;
        }
        
        public void setSource(String source){
            this.source = source;
        }
    }
  5. 新建SLSB的Remote接口:
    package com.winlin.db;
    
    import javax.ejb.Remote;
    
    @Remote
    public interface ProjectBeanRemote {
    }
  6. SLSB的实现(对外提供webservice):
    package com.winlin.db;
    
    import java.util.List;
    
    import javax.ejb.Stateless;
    import javax.jws.WebMethod;
    import javax.jws.WebService;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import javax.persistence.Query;
    
    @Stateless
    @WebService
    public class ProjectBean implements ProjectBeanRemote 
    {
        @PersistenceContext(unitName="mysql_ejb")
        protected EntityManager em;
        
        public ProjectBean() {
        }
    
        @WebMethod
        public void insertProject(Project p){
            em.persist(p);
        }
    
        @WebMethod
        @SuppressWarnings("unchecked")
        public List<Project> getProjectList(){
            Query query = em.createQuery("select p from Project p order by p.id asc");
            
            List<Project> p = (List<Project>) query.getResultList();
            
            return p;
        }
    
        @WebMethod
        public void updateSource(String source, int id){
            Project p = em.find(Project.class, id);
            
            p.setSource(source);
        }
    }
  7. 发布EJB。
下面的步骤访问发布的EJB:
  1. 导入webservice:
    wsimport -p com.winlin.db -keep http://database:8080/com.winlin.database/ProjectBean?WSDL
  2. 调用webservice:
    import java.util.Date;
    import java.util.List;
    
    import com.winlin.db.Project;
    import com.winlin.db.ProjectBean;
    import com.winlin.db.ProjectBeanService;
    
    public class EJBDbClient 
    {
        public static void main(String[] args) {
            Date start = new Date();
            System.out.println(start.toString());
            
            ProjectBeanService server = new ProjectBeanService();
            ProjectBean bean = server.getProjectBeanPort();
            
            Project p = new Project();
            p.setSource("test."+bean.getProjectList().size()+".flv");
            bean.insertProject(p);
            
            List<Project> list = bean.getProjectList();
            System.out.println("we get a list contains:" + list.size() + " elements.");
            for(int i=0;i<list.size();i++){
                System.out.println("id="+list.get(i).getId()+",url="+list.get(i).getSource());
            }
            
            Date end = new Date();
            System.out.println(end.toString());
            System.out.println("total:" + ((end.getTime() - start.getTime()) / 100 / 10.0) + "s");
        }
    }


第七方面:使用Eclipse调试EJB

如下方法可以在Eclipse中调试EJB生成的webservices

  1. Windows => Show View => Servers
  2. 右键 => New => Server
  3. 选择JBoss5.0 Server,默认参数选择完成
  4. 右键新建的Server => Open可以打开详细配置
  5. Open launch configuration 可以打开详细的运行参数配置。
    其中,Arguments设置VM arguments需要添加参数:-Djava.endorsed.dirs=C:\jboss5\lib\endorsed。即设为:
    -Dprogram.name=run.bat -Xms128m -Xmx512m  -XX:MaxPermSize=256m -Djava.endorsed.dirs=C:\jboss5\lib\endorsed
    否则webservice运行会报错(JBoss5.0+Jdk1.6)。
  6. 启动调试即可。

第八方面:EJB使用Hibernate

Jboss支持hibernate,所以直接编写hibernate的程序就可以运行在Jboss上了。

方法如下:

  1. 在mysql中新建数据库:
    drop DATABASE IF EXISTS `mysql_ejb`;
    create DATABASE mysql_ejb;
    use mysql_ejb;
    DROP TABLE IF EXISTS `Project`;
    CREATE TABLE `Project` (
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'the id of project',
    `source` varchar(2000) DEFAULT NULL COMMENT 'the friendly project name',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
  2. 注:不用新建mysql-ds.xml数据源。
  3. 新建ejb项目,在ejbModule(相当于src)下添加hibernate.cfg.xml,内容如下:
    <?xml version='1.0' encoding='UTF-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC
              "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
              "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
    <session-factory>
       <property name="dialect">
        org.hibernate.dialect.MySQLDialect
       </property>
       <property name="connection.url">
        jdbc:mysql://localhost:3306/mysql_ejb
       </property>
       <property name="connection.username">winlin</property>
       <property name="connection.password">mypassword</property>
       <property name="connection.driver_class">
        com.mysql.jdbc.Driver
       </property>
       <property name="myeclipse.connection.profile">MySQL</property>
       <mapping resource="com/winlin/Project.hbm.xml" />
    </session-factory>
    </hibernate-configuration>
  4. 为表Project新建类:
    package com.winlin;
    
    public class Project 
    {
        private int id;
        private String source;
        
        public int getId(){
            return this.id;
        }
        
        public void setId(int id){
            this.id = id;
        }
        
        public String getSource(){
            return this.source;
        }
        
        public void setSource(String source){
            this.source = source;
        }
    }
    
  5. 在同目录下新建映射文件:Project.hbm.xml
    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
        <class name="com.winlin.Project" table="project" catalog="mysql_ejb">
            <id name="id" type="java.lang.Integer">
                <column name="id" />
                <generator class="assigned" />
            </id>
            <property name="source" type="java.lang.String">
                <column name="source" length="2000" />
            </property>
        </class>
    </hibernate-mapping>
  6. 添加SLSB无状态SessionBean:ProjectBean,提供webservice,实现Remote接口:
    package com.winlin;
    
    import java.util.List;
    
    import javax.ejb.Stateless;
    import javax.jws.WebMethod;
    import javax.jws.WebService;
    
    import org.hibernate.Query;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    
    @WebService
    @Stateless
    public class ProjectBean implements ProjectBeanRemote
    {
        private static final SessionFactory factory = build_factory();
        
        private static SessionFactory build_factory(){
            try{
                return new Configuration().configure().buildSessionFactory();
            }
            catch(Exception ex){
                System.out.println("[error] initialize factory failed: " + ex.getMessage());
                throw new ExceptionInInitializerError(ex);
            }
        }
        
        public ProjectBean() {
        }
        
        @WebMethod
        public void insert_project(String source){
            Session session = factory.openSession();
            Transaction tx = session.beginTransaction();
            
            Project p = new Project();
            p.setSource(source);
            
            session.save(p);
            tx.commit();
            
            session.close();
        }
        
        @SuppressWarnings({ "unchecked", "rawtypes" })
        @WebMethod
        public List<Project> get_projects(){
            Session session = factory.openSession();
            Query query = session.createQuery("from Project as project order by id desc");
            query.setFirstResult(3);
            query.setMaxResults(10);
            List list = query.list();
            return list;
        }
    }
    
  7. 调用方法。
    先导入ws:
    wsimport -p com.winlin -keep http://127.0.0.1:8080/hibernate.db/ProjectBean?wsdl
    然后client调用:
    import java.util.Date;
    import java.util.List;
    
    import com.winlin.Project;
    import com.winlin.ProjectBean;
    import com.winlin.ProjectBeanService;
    
    public class HibernateDbClient 
    {
        public static void main(String[] args) {
            Date start = new Date();
            System.out.println(start.toString());
            
            ProjectBeanService service = new ProjectBeanService();
            ProjectBean bean = service.getProjectBeanPort();
            if(args.length <= 0){
                bean.insertProject("hello.hibernate.flv");
            }
            else{
                bean.insertProject(args[0]);
            }
    
            List<Project> list = bean.getProjects();
            for(int i=0 ;i < list.size(); i++){
                System.out.println(list.get(i).getSource());
            }
            
            Date end = new Date();
            System.out.println(end.toString());
            System.out.println("total:" + ((end.getTime() - start.getTime()) / 100 / 10.0) + "s");
        }
    }
    

第九方面:使用JAR

将接口定义在一个jar,供其他的project调用,方法如下:

  1. 新建java工程,定义接口IMan如下:
    public interface IMan
    {
        public String getName();
        public void bookFood();
    }
  2. 生成jar文件,执行如下命令:
    cd D:\tvie\lab\java\coms.shared\src
    jar cvf ../com.winlin.shared.jar *.class
  3. 新建调用java工程,定义类如下:
    public class Client implements IMan
    {
        public static void main(String[] args) {
            Client c = new Client();
            c.bookFood();
        }
        
        public String getName(){
            return "Client";
        }
        
        public void bookFood(){
            System.out.println(this.getName() + ": Client book food!");
        }
    }
  4. 编译程序:
    cd d:\tvie\lab\java\coms.client\src
    javac -classpath ..\..\coms.shared\com.winlin.shared.jar Client.java
  5. 执行程序:
    java -classpath .;..\..\coms.shared\com.winlin.shared.jar Client
  6. 结果如下:
    Client: Client book food!


第十方面:命令行编译和执行

在Windows下编译和Linux下编译有所不同。例如,若某程序引用了Jboss的库(EJB,JNI,JMS等),则编译和执行方法如下:

在Windows下编译和执行:

  1. 直接编译:
    cd D:\tvie\lab\java\jms.receiver\src
    javac -cp .;c:\jboss5\client\* QueueReceiver.java
  2. 可以是-cp或者-classpath。
    注意-cp后面必须是文件,可以用通配符(并且不能带扩展名),以下命令均为错误:
    javac QueueReceiver.java #没有带指定Jboss的库
    javac -cp . QueueReceiver.java #没有指定Jboss的引用库
    javac -cp .:c:\jboss5\client\* QueueReceiver.java #分隔符必须是分号。
    javac -cp .;c:\jboss5\client\*.jar QueueReceiver.java #通配符不能带扩展名。
  3. 直接执行:
    java -cp .;c:\jboss5\client\* QueueReceiver

Linux下编译和执行:

  1. 直接编译:
    /home/tvie/java
    javac -cp .:/usr/local/jboss/client/* QueueReceiver.java
  2. 分隔符必须是冒号,其他和windows一致,一下命令为错误:
    javac QueueReceiver.java #没有指定Jboss的库
    javac . QueueReceiver.java #没有指定Jboss的库
    javac -cp .;/usr/local/jboss/client/* QueueReceiver.java #使用的是分号,而不是冒号
    javac -cp .:/usr/local/jboss/client/*.jar QueueReceiver.java #通配符后面不能使用扩展名
  3. 直接执行:
    java -cp .:/usr/local/jboss/client/* QueueReceiver

使用环境变量。可以使用环境变量,这样可以不带-cp就可以编译和执行。方法如下:

  1. Windows设置环境变量(设置环境变量后关闭cmd.exe重新打开cmd.exe):
    右键我的电脑 => 属性 => 高级 => 在“系统变量” 双击“CLASSPATH” 设置内容如下:
    .;c:\jboss5\client\*
  2. Linux下执行如下命令:
    sudo vi /etc/profile
    #在结尾添加如下一行:
    export CLASSPATH=.:/usr/local/jboss/client/*
    #退出vi后,执行如下命令:
    source /etc/profile
  3. 编译和执行(linux和windows都一样):
    javac QueueReceiver.java
    java QueueReceiver
  4. 要注意分隔符和-cp只能是文件(通配符也是)。


第十方面:关于JMS和EJB-MDB

JMS是消息框架,定义了消息框架,EJB-MDB是JMS的消息消费者(Consumer/Receiver),其实可以自己定义Producer和Receiver/Consumer。

定义消息队列,拷贝到/usr/local/jboss/server/default/deploy/winlin-service.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<server>
    <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=winlin">
        <attribute name="JNDIName">queue/winlin</attribute>
        <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
    </mbean>
</server>

定义消息生产者(Producer)不断生产消息:

import java.util.Date;
import java.util.Properties;

import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;

public class QueueSender 
{
    public static void main(String[] args) throws Exception{
        String msg = "Hello, this is server!";
        if(args.length > 0){
            msg = args[0];
        }

        for(int i=0; ;i ++){
            Properties props = new Properties();
            props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
            props.setProperty(Context.PROVIDER_URL, "localhost:1099");
            props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
            
            InitialContext context = new InitialContext(props);
            QueueConnectionFactory factory = (QueueConnectionFactory)context.lookup("ConnectionFactory");
            QueueConnection conn = factory.createQueueConnection();
            QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
            Destination queue = (Queue)context.lookup("queue/winlin");
            
            MessageProducer producer = session.createProducer(queue);
            
            String formatted_msg = "msg#"+i+", "+msg;
            producer.send(session.createTextMessage(formatted_msg));
            
            session.close();
            conn.close();
            
            System.out.println("Message sended("+new Date().toString()+"): " + formatted_msg);
        }
    }
}

定义消息消费者(Receiver):

import java.util.Date;
import java.util.Properties;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;

class MyMessageListener implements MessageListener
{
    private QueueSession session;
    private QueueConnection conn;
    
    public void onMessage(Message msg){
        try{
            //Thread.sleep(100);
            System.out.println(new Date().toString() + ":" + ((TextMessage)msg).getText());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
    public void start() throws Exception{
        Properties props = new Properties();
        props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
        props.setProperty(Context.PROVIDER_URL, "localhost:1099");
        props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
        
        InitialContext context = new InitialContext(props);
        QueueConnectionFactory factory = (QueueConnectionFactory)context.lookup("ConnectionFactory");
        QueueConnection conn = factory.createQueueConnection();
        QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
        Queue queue = (Queue)context.lookup("queue/winlin");
        
        javax.jms.QueueReceiver receiver = session.createReceiver(queue);
        
        receiver.setMessageListener(this);
        
        this.session = session;
        this.conn = conn;
        
        conn.start();
    }
    
    public void stop() throws Exception{
        session.close();
        conn.close();
    }
}

public class QueueReceiver
{
    public static void main(String[] args) throws Exception {
        MyMessageListener msg = new MyMessageListener();
        msg.start();
        System.out.println("Listener started!");
        Thread.sleep(20*1000);
        msg.stop();
        
        System.out.println("Receiver exited!");
    }
}

编译和执行:

#编译
javac -cp .:/usr/local/jboss/client/* QueueReceiver.java
javac -cp .:/usr/local/jboss/client/* QueueSender.java
#执行,可以在不同的机器
java -cp .:/usr/local/jboss/client/* QueueReceiver
java -cp .:/usr/local/jboss/client/* QueueSender


第十一方面:关于RMI

远程调用,RMI是EJB的基础,JMS是消息机制,也可以作为调用的方式。

JMS若需要消息处理的结果,就会很麻烦。例如Producer发送一条消息到队列A,Receiver从队列A接受到消息后再发一条消息到队列B。首先需要两个队列,其次若Producer有多个,就有麻烦了。

例如ProducerA和ProducerB都发送了消息到队列A,Receiver接受消息处理后将结果发到队列B,ProducerA和ProducerB都能收到消息,可是无法确定能收到特定的消息。

可以用topic接口,可并不使用这个场景(会接受到自己不需要的消息),所以消息作为调用还是有局限性。topic在广播给Receiver,例如更新状态时,每个Receiver都需要这个消息,是符合应用场景的。

RMI是同步调用(webservice同步调用作为异构平台的应用,ARMI据说是异步具体还再看),使用方法如下:

实现RMIServer:

import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

interface IServer extends Remote
{
    public String hello() throws RemoteException;
}

class Server extends UnicastRemoteObject implements IServer
{
    public Server() throws RemoteException{
    }
    
    public String hello() throws RemoteException{
        return "#" + Thread.currentThread().getId() + ": hello, RMI world!";
    }
}

public class RMIServer 
{
    public static void main(String[] args) throws Exception {
        IServer server = new Server();
        LocateRegistry.createRegistry(9099);
        
        String url = "rmi://localhost:9099/RMIServer";
        Naming.bind(url, server);
        Thread.sleep(10000);
        System.exit(0);
    }
}

实现RMIClient:

import java.rmi.Naming;


public class RMIClient 
{
    public static void main(String[] args) throws Exception {
        for(;;){
            String url = "rmi://localhost:9099/RMIServer";
            IServer server = (IServer)Naming.lookup(url);
            System.out.println("RMIServer: " + server.hello());
        }
    }
}


第十二方面 java7的内存问题

使用wsimport导入webservice后调用,若使用java6调用没有问题,若使用java7调用(7.0.10.8)内存会一直增长直到吃光。


最后一方面:没有了。

靠人品了~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

winlinvip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值