zoukankan      html  css  js  c++  java
  • EJB3.0快速入门

    1.首先介绍运行环境及相关的配置:

    EJB的运行环境:
      JAVAEE应用服务器包含Web容器和EJB容器,EJB3.0应用需要运行在EJB容器里。
      Tomcat目前只是Web容器,它不能运行EJB应用。
      Jboss作为最常用EJB容器,其自身所带Web服务器部分就是直接使用Tomcat(Jboss的默认端口也为:8080)。

    相关配置:
      1.配置classpath:%JDK安装目录%/lib/dt.jar和tools.jar
      2.JDK版本需要1.5以上。
      3.为Jboss设置Jboss_HOME系统环境变量。(设置为Jboss的安装路径)
      4.在PATH中设置Jboss的bin目录。

    2.EJB简介:

      EJB(Enterprice JavaBeans):是一个用于分布式业务应用的标准服务端组建模型。采用EJB编写的应用可以部署在任何支持EJB的规范服务器平台,如:Jboss,Weblogic等。EJB设计的初衷是用于分布式场合,相对于Spring来说,其适合大型企业应用,一般大型企业都存在多个信息系统,而这些信息系统有相互关联,为了避免业务功能重复开发,实现最大程度的重用,有必要把业务层独立出来,让多个信息系统共享一个业务中心,这样应用就需要具备分布式能力。

      EJB用于编写业务层代码(Model),采用EJB开发基于MVC结构的应用,那么EJB就是开发应用的业务层。EJB为我们提供了很多在企业开发中需要使用到的服务,因为这些服务由容器提供。

      非EJB的应用模式,MVC都是运行在同一个web容器,如tomcat。而在EJB模式中View,Controller都运行与tomcat,而Model运行与Jboss等容器中。

    3.EJB中有三种bean:

    1.session bean(会话bean):
      负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过jdbc直接操作数据库,但大多数情况下都是通过实体bean来完成对数据库的操作。  

      Session bean又分为:
        <1.无状态会话bean(@Stateless):
          我们使用最多的就是无状态会话bean,因为他的实例可以供多个用户使用,所以前一个用户设置的值有可能被后一个用户修改,所以他无法正确保证某个用户设置的值,因此是无状态的。
        <2.有状态会话bean(@Stateful):
          使用的不多,因为其一个实例只被一个用户使用。

    2.entity bean(实体bean):
      实际上属于java持久化规范(简称JPA)里的技术,JPA的出现主要是为了简化现有持久化开发工作和整合ORM技术,结束现在Hibernate、TopLink等ORM框架各自为营的局面。
    3.message-driven bean(消息驱动bean):
      它是专门用于异步处理java消息的组建,具有处理大量并发消息的能力。

    4.开发一个无状态的会话bean:

      需要使用的jar文件都在Jboss根目录下的client目录下(为简单起见,直接引入所有jar文件)。

    1.接口(接口可以是远程接口也可以是本地接口,这里是remote接口):

    package cn.itcast.ejb3;
    public interface HelloWorld { public String sayHello(String name); }

    2.实现类:

    package cn.itcast.ejb3.impl;
    
    import javax.ejb.Remote;
    import javax.ejb.Stateless;
    import cn.itcast.ejb3.HelloWorld;
    
    @Stateless    //指定为无状态会话bean
    @Remote(HelloWorld.class)    //指定为远程接口,默认实现本地接口
    public class HelloWorldBean implements HelloWorld {
    
        public String sayHello(String name) {
            
            return name + "说:你好,世界!";
        }
    
    }

    3.Session bean的客户端开发:

    package cn.itcast.test;
    
    import java.util.Properties;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import cn.itcast.ejb3.HelloWorld;
    
    public class EJBClient {
        
        public static void main(String[] args) {
            try {
                InitialContext ctx = new InitialContext();
                HelloWorld helloworld = (HelloWorld)ctx.lookup("HelloWorldBean/remote");  //此时客户端处于JDK的JVM中,而HelloWorld处于Jboss的JVM中,属于远程调用
                System.out.print(helloworld.sayHello("小明"));
            } catch (NamingException e) {
                System.out.print(e.getMessage());
            }
            
        }
    
    }  

      完成了上面的代码之后我们将整个项目输出为jar文件并发布到发布目录Jboss-4.2.3.GAserverdefaultdeploy下,这样就完成了EJB的部署。

      打包方式可以使用Eclipse直接输出jar文件,也可以使用ant(自动打包、编译、发布)。

      ant的build.xml:

    <?xml version="1.0" encoding="UTF-8" ?>
    <project name="Jboss_HelloWorld_2" basedir=".">
        <property name="src.dir" value="${basedir}src" />
        <property environment="env" />
        <property name="Jboss.home" value="${env.Jboss_HOME}" />
        <property name="Jboss.server.config" value="default" />
        <property name="build.dir" value="${basedir}uild" />
        
        <path id="build.classpath">
            <fileset dir="${Jboss.home}client">
                <include name="*.jar" />
            </fileset>
            <pathelement location="${build.dir}" />
        </path>
        
        <target name="prepare">
            <delete dir="${build.dir}"/>
            <mkdir dir="${build.dir}"/>
        </target>
    
        <target name="compile" depends="prepare" description="编译">
            <javac srcdir="${src.dir}" destdir="${build.dir}">
                <classpath refid="build.classpath"/>
            </javac>
        </target>
        
        <target name="ejbjar" depends="compile" description="创建EJB发布包">
            <jar jarfile="${basedir}${ant.project.name}.jar">
                <fileset dir="${build.dir}">
                    <include name="**/*.class"/>
                </fileset>
            </jar>
        </target>
        
        <target name="deploy" depends="ejbjar" description="发布ejb">
            <copy file="${basedir}${ant.project.name}.jar" todir="${Jboss.home}server${Jboss.server.config}deploy"/>
        </target>
    
        <target name="undeploy" description="卸载ejb">
            <delete file="${Jboss.home}server${Jboss.server.config}deploy${ant.project.name}.jar"/>
        </target>
        
    </project>

      EJB卸载直接将发布文件删除即可。

      在设置JNDI查找前,我们必须设置应用服务器的上下文信息,主要为JNDI驱动的类名(java.naming.factory.initial)和命名服务提供者的URL(java.naming.provider.url)。如同访问数据库一样,根据访问的命名服务器的不同,为上下问设置的驱动类和URL也是不同的。

      EJB发布到Jboss时,如果我们没有为它指定全局的JNDI名称或修改其默认的EJB名称,Jboss就会按照默认的命名规则为EJB生成全局的JNDI名称。可以使用注解或者xml配置文件修改Session Bean的JNDI名称。

    JNDI是什么?
      JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API。命名服务将名称和对象联系起来,使得我们可以用名称访问对象。

      如果客户端运行在应用服务器内,我们不需要为InitialContext设置应用服务器的上下文信息,也不建议设置。因为应用服务器启动的时候会把JNDI驱动类等上下文信息添加到系统属性,创建InitialContext对象时回没有指定Properties参数、InitialContext内部会调用System.getProperty()方法从系统属性里获取必要的上下文信息。

    5.通过远程接口调用EJB的过程:

      首先客户端需要与ejb建立起socket通信,在通信管道上他们之间需要来回发送IIOP协议信息,因为数据要在网络进行传输,存放数据的java对象必须要进行序列化。
      在这个过程中有网络通信的开销、协议解析的开销、对象序列化的开销。因为EJB是分布式的技术,它允许客户端与EJB应用在不同的机器上,所有这些开销也是必然的。但在实际情况中,客户端与EJB可能运行在同一个Jboss中,这时候客户端和EJB在同一个JVM内,他们之间完全可以通过内存进行交互,这样就可以避免网络通信的开销,所以引入了本地接口。通过本地接口直接调用EJB,直接在内存中交互,这样就可以减少开销。需要注意的一点是,只有客户端与EJB应用在同一个JVM内运行的时候,我们才能调用本地接口,否则只能调用远程接口(可以认为当客户端与EJB发布在同一个Jboss中的时候,他们就是在同一个JVM中)。

    6.本地调用ejb:

      将客户端新建在一个新的web project中,并将其部署在Jboss中,则此时客户端和EJB都部署在同一个JVM中,故属于本地调用。而上面的例子的客户端部署在JDK的JVM中,与EJB不属于同一个JVM,属于远程调用。

    7.bean实例的两种管理技术:

      无状态bean使用实例池技术管理bean:实例池中的对象可以被公用。
      有状态bean使用激活(Activation)管理bean:每个用户都有自己的Bean实例,EJB服务器需要节省资源的时候,就从内存收回bean实例,将其保存的会话状态序列化到硬盘中,并且释放其所占用的内存,若此时客户端再次对EJB发起请求,EJB容器会重新实例化一个Bean实例,并从硬盘中将之前的、状态恢复。

    8.EJB调用EJB:

    1.Other接口:

    package cn.itcast.ejb3;
    
    public interface Other {
        public String sayMe();
    }

    2.Other实现类:

    package cn.itcast.ejb3.impl;
    
    import javax.ejb.Local;
    import javax.ejb.Stateless;
    import cn.itcast.ejb3.Other;
    
    @Stateless    //声明为无状态会话bean
    @Local(Other.class)
    public class OtherBean implements Other {
    
        public String sayMe() {
            return "other";
        }
    
    }

    3.HelloWorld实现类(调用Other实现类的方法):

    package cn.itcast.ejb3.impl;
    
    import javax.ejb.Local;
    import javax.ejb.Remote;
    import javax.ejb.Stateless;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import cn.itcast.ejb3.HelloWorld;
    import cn.itcast.ejb3.Other;
    
    @Stateless    //指定为无状态会话bean
    @Remote(HelloWorld.class)    //指定为本地接口
    public class HelloWorldBean implements HelloWorld {
        
        
        
        public String sayHello(String name) {
            try {
                InitialContext ctx = new InitialContext();
                Other other = (Other)ctx.lookup("OtherBean/local");
                return name + "说:你好," + other.sayMe();
            } catch (NamingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    }

    4.Client客户端:

    package cn.itcast.test;
    
    import java.util.Properties;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import cn.itcast.ejb3.HelloWorld;
    
    public class EJBClient {
        
        public static void main(String[] args) {
            try {
                InitialContext ctx = new InitialContext();
                HelloWorld helloworld = (HelloWorld)ctx.lookup("HelloWorldBean/remote");
                System.out.print(helloworld.sayHello("注入者"));
            } catch (NamingException e) {
                System.out.print(e.getMessage());
            }
            
        }
    
    }

      lookup()方法返回的对象不是bean实例,实际上,客户端与Sessionbean交互,它并不直接与Bean实例打交道,而是经由bean的远程或本地接口。当你调用远程或本地接口的方法时,接口使用的是存根(stub)对象,该存根实现了sessionbean的远程或本地接口,他负责将方法调用经过网络发送到远程的EJB容器,或将请求路由到位于本地JVM内的EJB容器。存根是在部署期间使用JDK所带的java.lang.reflect.Proxy动态生成的。

    9. 使用注解依赖注入EJB:     

      若有两个EJB同时实现了同一个EJB接口的时候,可以使用beanName来指定是那个EJB实现类(默认就是类名,也可以自己指定)。
      @EJB(beanName="OtherBean")

    package cn.itcast.ejb3.impl;
    
    import javax.ejb.EJB;
    import javax.ejb.Local;
    import javax.ejb.Remote;
    import javax.ejb.Stateless;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import cn.itcast.ejb3.HelloWorld;
    import cn.itcast.ejb3.Other;
    
    @Stateless    //指定为无状态会话bean
    @Remote(HelloWorld.class)    //指定为本地接口
    public class HelloWorldBean implements HelloWorld {
        
        @EJB Other other;    //使用注解注入EJB
        public String sayHello(String name) {
            return name + "说:你好," + other.sayMe();
        }
    
    }

    10.配置Jboss数据源:

    1.修改数据源文件mysql-ds.xml(E:wuenqiangJboss-4.2.3.GAdocsexamplesjca)。
    2.引入mysql的驱动文件到E:wuenqiangJboss-4.2.3.GAserverdefaultlib目录下。
    3.将mysql-ds.xml拷贝到E:wuenqiangJboss-4.2.3.GAserverdefaultdeploy目录下。

    mysql-ds.xml中可以配置数据库连接池的各种信息:

    ......
        <jndi-name>itcastDS</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/Jbossdb</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>root</user-name>
        <password>abc123</password>
        <min-pool-size>3</min-pool-size>
        <max-pool-size>100</max-pool-size>
    .....

      实体bean属于持久化规范(简称JPA)技术,实体bean通过元数据在javabean和数据库之间建立映射关系,然后我们就可以使用面向对象的编程思想来操纵数据库(大多数数据库是面向关系的)。
    Jboss默认使用Hibernate做为持久化层。

    11消息驱动bean:

      Java消息服务(Java Message Service,简称JMS)是用于访问企业消息系统的开发商中立的API。企业消息系统可以协助应用软件通过网络进行消息交互。

    JMS编程过程:
      应用程序A发送消息发到消息服务器的某个目的地,然后消息服务器把消息转发到应用程序B。应用程序A、B之间没有直接的代码关联,实现了两者的解耦。

    消息传递系统的中心就是信息。一条Message由三部分组成:头(header)、属性(proeprty)、主题(body)。

    消息可以有许多类型,他们都继承了Message接口。

    MS支持两种消息传递模型:
      1.点对点(queue):
        规定了一条消息只能传递给一个接受方。
      2.发布/订阅(topic):
        允许一条消息传递给多个接受方。
    这两种模型都通过扩展公用基类来实现。例如:javax.jsm.Queue和javax.jms.Topic都扩展自javax.jms.Destination类。

    itcast-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=itcastQueue">
        <attribute name="JNDIName">queue/itcastQueue</attribute>
        <depends optional-attribute-name="DestinationManager">Jboss.mq:service=DestinationManager</depends>
      </mbean>
    
      <mbean code="org.Jboss.mq.server.jmx.Topic"
             name="Jboss.mq.destination:service=Topic,name=itcastTopic">
        <attribute name="JNDIName">topic/itcastTopic</attribute>
        <depends optional-attribute-name="DestinationManager">Jboss.mq:service=DestinationManager</depends>
      </mbean>
    </server>

    12.点对点(queue):

    发送消息:

    package cn.itcast.app;
    
    import javax.jms.Destination;
    import javax.jms.MessageProducer;
    import javax.jms.QueueConnection;
    import javax.jms.QueueConnectionFactory;
    import javax.jms.QueueSession;
    import javax.naming.InitialContext;
    
    public class QueueSender {
    
        public static void main(String[] args) {
            try {
                InitialContext ctx = new InitialContext();
                 QueueConnectionFactory factory = (QueueConnectionFactory)ctx.lookup("QueueConnectionFactory");
                 QueueConnection conn = factory.createQueueConnection();
                 QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
                 Destination destination = (Destination)ctx.lookup("queue/itcastQueue");
                 MessageProducer producer = session.createProducer(destination);
                 producer.send(session.createTextMessage("你好,吴恩强"));
                 session.close();
                 conn.close();
                 System.out.println("发送完1");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    接收消息:

    package cn.itcast.app;
    
    import javax.jms.Destination;
    import javax.jms.MessageProducer;
    import javax.jms.QueueConnection;
    import javax.jms.QueueConnectionFactory;
    import javax.jms.QueueSession;
    import javax.naming.InitialContext;
    
    public class QueueSender {
    
        public static void main(String[] args) {
            try {
                InitialContext ctx = new InitialContext();
                 QueueConnectionFactory factory = (QueueConnectionFactory)ctx.lookup("QueueConnectionFactory");
                 QueueConnection conn = factory.createQueueConnection();
                 QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
                 Destination destination = (Destination)ctx.lookup("queue/itcastQueue");
                 MessageProducer producer = session.createProducer(destination);
                 producer.send(session.createTextMessage("你好,小燕子"));
                 session.close();
                 conn.close();
                 System.out.println("发送完1");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    13.2.发布/订阅(topic):

    发送消息:

    package cn.itcast.app;
    
    import javax.jms.Destination;
    import javax.jms.MessageProducer;
    import javax.jms.TopicConnection;
    import javax.jms.TopicConnectionFactory;
    import javax.jms.TopicSession;
    import javax.naming.InitialContext;
    
    
    
    public class TopicSender {
        public static void main(String[] args) {
            try {
                InitialContext ctx = new InitialContext();
                 TopicConnectionFactory factory = (TopicConnectionFactory)ctx.lookup("TopicConnectionFactory");
                 TopicConnection conn = factory.createTopicConnection();
                 TopicSession session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
                 Destination destination = (Destination)ctx.lookup("topic/itcastTopic");
                 MessageProducer producer = session.createProducer(destination);
                 producer.send(session.createTextMessage("你好,小燕子2"));
                 session.close();
                 conn.close();
                 System.out.println("发送完2");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    接收消息1:

    package cn.itcast.message;
    
    import javax.ejb.ActivationConfigProperty;
    import javax.ejb.MessageDriven;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.TextMessage;
    
    @MessageDriven(activationConfig = 
    {
            @ActivationConfigProperty(propertyName="destinationType",
                    propertyValue="javax.jms.Topic"),
            @ActivationConfigProperty(propertyName="destination",
                    propertyValue="topic/itcastTopic")
    })
    public class ReceiveBean implements MessageListener {
    
        public void onMessage(Message message) {
            try {
                System.out.println(this.getClass() + "***********" + (TextMessage)message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    接收消息2:

    package cn.itcast.message;
    
    import javax.ejb.ActivationConfigProperty;
    import javax.ejb.MessageDriven;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.TextMessage;
    
    @MessageDriven(activationConfig = 
    {
            @ActivationConfigProperty(propertyName="destinationType",
                    propertyValue="javax.jms.Topic"),
            @ActivationConfigProperty(propertyName="destination",
                    propertyValue="topic/itcastTopic")
    })
    public class ReceiveOtherBean implements MessageListener {
    
        public void onMessage(Message message) {
            try {
                System.out.println(this.getClass() + "***********" + ((TextMessage)message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    Stack
    汇编语言结构
    位操作指令bitwise logical instructions
    Linux中一些系统调用的汇编程序
    Ctrl + D
    一般的二进制数描述方法
    在汇编中定义table(array)
    (转)yujiaun 企业站MVC3.0版源码
    (转)knockout.js教程
    (转)开源中国WP7客户端全面开源,包括iPhone客户端与Android
  • 原文地址:https://www.cnblogs.com/mosquito-woo/p/3916732.html
Copyright © 2011-2022 走看看