jboss下的ejb3中MessageDrivenBean的一个简单案例

     最近在看一本介绍ejb3的新书---《EJB3 in action》, 我觉得还写得可以,如果再结合网上黎活明写的开源文档---《JbossEJB3.0实例教程》一起学习,肯定会达到事半功倍的效果。(这两本书都可以在网上搜到,也可以上得益网下载)。

    1.本案例相对简单,但基本用到了ejb3.0的一些基础知识,包括stateless session bean,entity bean,messageDriven bean,transaction,interceptor。

   2.本案例以jboss为j2ee应用服务器,以Eclipse3.2作为开发的IDE,oracle10g为database,当然jdk应为1.5以上,因为java的metadata annotation(注释)是在jdk1.5才出来的。

  3.本案例的设计思路:在实际应用中,例如一个web电子商务系统,用户在网上注册后,系统往往将用户的一些基本信息如姓名,年龄,email等发送给其它系统,如和它相关的一个邮递系统或广告宣传系统(仅仅是假设哈!)。那么就可以利用ejb3.0的messageDrivenBean来接收其它系统发送过来的message。本例先写一个entity bean----Customer.java,接着写一个statelessBean(MessageSender.java)来发送消息(即发送一个Customer实例),然后写一个messageDrivenBean(MessageReciverMDB.java)来接收消息,最后利用DI注入一个service类(CustomerService)来完成业务逻辑,将customer对象存入database里。

 4.本案例的应用目录如下:

messageDrivenBean

        src  

                com.wang.ejb3.dao

               com.wang.ejb3.service

               com.wang.entity

               com.wang.mdb

               com.wang.mdb.app

               META-INF

       lib

      build.xml

   5.各个包中的java类

    (1)com.wang.entity

          Customer.java

package  com.wang.entity;

import  java.util.Date;
import  java.io.Serializable;
import  javax.persistence.Entity;
import  javax.persistence.Column;
import  javax.persistence.Table;
import  javax.persistence.Id;
import  javax.persistence.GeneratedValue;
import  javax.persistence.GenerationType;
import  javax.persistence.Temporal;
import  javax.persistence.TemporalType;

@Entity
@Table(name
= " customers " )
public   class  Customer  implements  Serializable{
    
public   static   final   long  serialVersionUID =- 1814239825517340645L ;
    
private  Long id;
    
private  String name;
    
private   int  age;
    
private  Date birthday;
    
    
public  Customer(){}
    
public  Customer(String name, int  age,Date birthday){
        
this .name = name;
        
this .age = age;
        
this .birthday = birthday;
    }
    
    
    
public   int  getAge() {
        
return  age;
    }
    
public   void  setAge( int  age) {
        
this .age  =  age;
    }
    
    @Temporal(value
= TemporalType.TIMESTAMP)
    
public  Date getBirthday() {
        
return  birthday;
    }
    
public   void  setBirthday(Date birthday) {
        
this .birthday  =  birthday;
    }
    
    @Id
    @GeneratedValue(strategy
= GenerationType.AUTO)
    
public  Long getId() {
        
return  id;
    }
    
public   void  setId(Long id) {
        
this .id  =  id;
    }
    @Column(nullable
= false ,length = 40 )
    
public  String getName() {
        
return  name;
    }
    
public   void  setName(String name) {
        
this .name  =  name;
    }
    
    
}

 

  ( 2) com.wang.ejb3.dao

     CustomerDao.java

 

package  com.wang.ejb3.dao;

import  com.wang.entity.Customer;

public   interface  CustomerDao{
    
void  addCustomer(Customer customer) throws  Exception;
    
void  deleteCustomerById(Long id) throws  Exception;
    Customer getCustomerById(Long id)
throws  Exception;
    
}

 

   CustomerDaoBean.java

 

package  com.wang.ejb3.dao;

import  javax.ejb.Remote;
import  javax.ejb.Stateless;
import  javax.persistence.PersistenceContext;
import  javax.persistence.EntityManager;

import  com.wang.entity.Customer;

@Stateless
@Remote(CustomerDao.
class )
public   class  CustomerDaoBean  implements  CustomerDao{
    
    @PersistenceContext
    
protected  EntityManager entityManager;
    
    
public   void  addCustomer(Customer customer) throws  Exception{
        entityManager.persist(customer);
    }
    
public   void  deleteCustomerById(Long id) throws  Exception{
        
        entityManager.remove(getCustomerById(id));
    }
    
public  Customer getCustomerById(Long id) throws  Exception{
        
return  (Customer)entityManager.find(Customer. class , id);
    }
}

 

 (3)com.wang.ejb3.service

     CustomerService.java

 

package  com.wang.ejb3.service;

import  com.wang.entity.Customer;

public   interface  CustomerService{
    
void  addCustomer(Customer customer);
    
void  deleteCustomerById(Long id);
    Customer getCustomerById(Long id);
}

       CustomerServiceBean.java

 

package  com.wang.ejb3.service;

import  javax.ejb.Remote;
import  javax.ejb.EJB;
import  javax.annotation.Resource;
import  javax.ejb.Stateless;
import  javax.ejb.SessionContext;
import  com.wang.ejb3.dao.CustomerDao;
import  com.wang.entity.Customer;

import  javax.ejb.TransactionManagement;
import  javax.ejb.TransactionAttribute;
import  javax.ejb.TransactionManagementType;
import  javax.ejb.TransactionAttributeType;

@Stateless
@Remote(CustomerService.
class )
@TransactionManagement(TransactionManagementType.CONTAINER)
public   class  CustomerServiceBean  implements  CustomerService{
    @Resource
    
private  SessionContext context;
    @EJB(beanName
= " CustomerDaoBean " )
    
protected  CustomerDao customerDao;
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    
public   void  addCustomer(Customer customer){
        
try {
            customerDao.addCustomer(customer);
        }
catch (Exception e){
            e.printStackTrace();
            context.setRollbackOnly();
        }
    }
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    
public   void  deleteCustomerById(Long id){
        
try {
            customerDao.deleteCustomerById(id);
        }
catch (Exception e){
            e.printStackTrace();
            context.setRollbackOnly();
        }
    }
    
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    
public  Customer getCustomerById(Long id){
        
try {
            
return  customerDao.getCustomerById(id);
        }
catch (Exception e){
            e.printStackTrace();
            context.setRollbackOnly();
            
return   null ;
        }
    }
}

 

      以上为经典的分层设计模式,包括persistence object,data access object,business service object(完整的应用还应该有controller object和view层)。因为本案例只是简单的实现messageDrivenBean的功能,所以就没有涉及web层(controller和view),只用一个java类的main方法来发送message。

    下面来看看本案例的两个核心类,statelessBean(MessageSender.java)来发送消息(即发送一个Customer实例),然后写一个messageDrivenBean(MessageReciverMDB.java)来接收消息。它们为于com.wang.mdb包中

   (4)com.wang.mdb

   1. MSender.java

  

package  com.wang.mdb;

import  javax.ejb.Remote;
import  com.wang.entity.Customer;

@Remote
public   interface  MSender{
    
void  sendMessage(Customer sender);
}

   2.MessageSender.java

 

package  com.wang.mdb;

import  javax.jms.Connection;
import  javax.jms.ConnectionFactory;
import  javax.jms.Destination;
import  javax.jms.Session;
import  javax.jms.ObjectMessage;
import  javax.jms.MessageProducer;
import  javax.ejb.Stateless;
import  javax.annotation.Resource;
import  javax.interceptor.Interceptors;
import  com.wang.entity.Customer;

@Stateless
public   class  MessageSender  implements  MSender{
    
    @Resource(mappedName
= " QueueConnectionFactory " )
    
private  ConnectionFactory connectionFactory;
    
    @Resource(mappedName
= " queue/wang " )
    
private  Destination destination;
    @Interceptors(MessageInterceptorLog.
class )
    
public   void  sendMessage(Customer sender){
        
try {
            Connection connection
= connectionFactory.createConnection();
            Session session
= connection.createSession( true , Session.AUTO_ACKNOWLEDGE);
            
            MessageProducer producer
= session.createProducer(destination);
            ObjectMessage message
= session.createObjectMessage();
            message.setObject(sender);
            producer.send(message);
            
            producer.close();
            session.close();
            connection.close();
            System.out.print(
" message send success " );
        }
catch (Exception e){
            e.printStackTrace();
        }
    }
}

  3.MessageReciverMDB.java

 

package  com.wang.mdb;

import  javax.ejb.MessageDriven;
import  javax.ejb.ActivationConfigProperty;
import  javax.jms.Message;
import  javax.jms.JMSException;
import  javax.jms.MessageListener;
import  javax.jms.ObjectMessage;
import  javax.interceptor.Interceptors;
import  javax.ejb.EJB;
import  com.wang.ejb3.service.CustomerService;
import  com.wang.entity.Customer;

@MessageDriven(
        mappedName
= " MessageReciverMDB " ,
        messageListenerInterface
= javax.jms.MessageListener. class ,
        activationConfig
= {
                @ActivationConfigProperty(propertyName
= " destinationType " ,propertyValue = " javax.jms.Queue " ),
                @ActivationConfigProperty(propertyName
= " destination " ,propertyValue = " queue/wang " ),
                @ActivationConfigProperty(propertyName
= " acknowledgeMode " ,propertyValue = " DUPS_OK_ACKNOWLEDGE " )
                
        }
        )
        
public   class  MessageReciverMDB  implements  MessageListener{
    
    @EJB(beanName
= " CustomerServiceBean " )
    
protected  CustomerService customerSercvice;
    
    
private  Customer sender;
    
    @Interceptors(MessageInterceptorLog.
class )
    
public   void  onMessage(Message message){
        
try {
            ObjectMessage objectMessage
= (ObjectMessage)message;
             sender
= (Customer)objectMessage.getObject();
            System.out.println(sender.getName());
            System.out.println(sender.getAge());
            System.out.println(sender.getBirthday());
            
this .customerSercvice.addCustomer(sender);
        }
catch (JMSException jme){
            jme.printStackTrace();
            
        }
catch (Exception e){
            e.printStackTrace();
        }
    }
    
    
    
}

       以上为本例的核心部分,其中annotation的一些配置和ejb3 in action上不一样,因为是运行在jboss上,所以要以jboss的配置为准。如@ActivationConfigPropert(propertyName="destination",propertyValue="queue/wang"),如果你将destination写成distinationName的话会报错,在http://www.manning-sandbox.com/thread.jspa?threadID=20021&tstart=0 上你可以看到关于这个配置的错误:RequiredConfigPropertyMetaData@201d6d[name=destination descriptions=[DescriptionMetaData@5d8e63[language=de]]] for messagingType 'javax.jms.MessageListener' not found in activation config [ActivationConfigProperty(destinationType=javax.jms.Queue), ActivationConfigProperty(destinationName=queue/OrderProcessorQueue)] ra=jboss.jca:service=RARDeployment,name='jms-ra.rar'

有人回复说:You are not the only one having this problem. We did the same fix for our JBoss sample code. This appears to be a JBoss bug...

但是这不是jboss的bug,而是由于参数名的不同所引起的,所以大家关于annotation的参数配置一定要依据不同厂商的服务器的来确定,有可能不同的服务器有它自己特殊的要求,这也是用annotation来封装配置信息的一个不足之处,封装的越多,程序的实现越简单,但程序员知道的也就越少,对错误的查找和代码的测试更加困难,有点失去对程序的主控权,写程序越来越像敲字母,不得不依赖于厂商的解决(比如bug)。

 

4.MessageInterceptorLog.java(一个简单的AOP)

 

package  com.wang.mdb;

import  javax.interceptor.AroundInvoke;
import  javax.interceptor.InvocationContext;
import  java.sql.Timestamp;
import  com.wang.entity.Customer;


public   class  MessageInterceptorLog{
    @AroundInvoke
    
public  Object logMethodEntry(InvocationContext context) throws  Exception{
        System.out.println(
new  Timestamp(System.currentTimeMillis()) + "  Enter method: " + context.getMethod().getName());
        Object[] args
= context.getParameters();
        
for ( int  i = 0 ;i < args.length;i ++ ){
            
if (args[i]  instanceof  Customer){
                Customer customer
= (Customer)args[i];
                
if (customer.getName().equals( " wang " )){
                    customer.setName(
" wangwang " );
                }
            }
        }
        
        Object returnValue
= context.proceed();
        System.out.println(
new  Timestamp(System.currentTimeMillis()) + "  Out method: " + context.getMethod().getName());
        
return  returnValue;
    }
}

 

(5)com.wang.mdb.app

  MessageSenderApp.java(用一个java类来调用消息发送类)

 

package  com.wang.mdb.app;

import  com.wang.mdb. * ;
import  java.util. * ;
import  javax.naming.InitialContext;
import  com.wang.entity.Customer;

public   class  MessageSenderApp{
    
public   static   void  main(String[] args){
        Properties props 
=   new  Properties();
        props.setProperty(
" java.naming.factory.initial " ,
        
" org.jnp.interfaces.NamingContextFactory " );
        props.setProperty(
" java.naming.provider.url " " localhost:1099 " );
        props.setProperty(
" java.naming.factory.url.pkgs " ,
        
" org.jboss.naming:org.jnp.interfaces " );
        
try {
        InitialContext ctx 
=   new  InitialContext(props);
        MSender sender
= (MSender)ctx.lookup( " MessageSender/remote " );
        Customer sender1
= new  Customer( " wangwui " , 24 , new  Date());
        sender.sendMessage(sender1);
        }
catch (Exception e){
            e.printStackTrace();
        }
    }
}

 

   jboss下 oracle数据源的配置:

  1.写一个oracle-ds.xml

<?xml version="1.0" encoding="UTF-8"?>

<datasources>
  <local-tx-datasource>
    <jndi-name>OracleDS</jndi-name>
    <connection-url>jdbc:oracle:thin:@wang(你的计算机名):1521:orcl</connection-url>
 
    <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
    <user-name>system</user-name>
    <password>d123456</password>
   
      <metadata>
         <type-mapping>Oracle10g</type-mapping>
      </metadata>
  </local-tx-datasource>

</datasources>

将它放到你jboss中的部署目录下 例如:F:/j2EE/jboss-4.2.0.GA/server/default/deploy下

将oracle的驱动jar包-----ojdbc14.jar(在你安装的oracle目录下去找或者网上下www.oracle.com)复制到jboss的default的lib里 例如:F:/j2EE/jboss-4.2.0.GA/server/default/lib下

java持久化单元的配置:

在META-INF中写一个persistence.xml

<?xml version="1.0"?>
<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="person">
  
    <jta-data-source>java:/OracleDS</jta-data-source>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="update"/>(自动创建数据库)
      <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
    </properties>
  
    </persistence-unit>
</persistence>

最后application用ant工具编译,打包成jar文件,部署到jboss中

 

project name="EntityTest" default="ejbjar" basedir=".">

    
< property  environment ="env"   />
    
< property  name ="app.dir"  value ="${basedir}"   />
    
< property  name ="src.dir"  value ="${app.dir}/src"   />
    
< property  name ="jboss.home"  value ="${env.JBOSS_HOME}"   />
    
< property  name ="jboss.server.config"  value ="default"   />
    
< property  name ="build.dir"  value ="${app.dir}/build"   />
    
< property  name ="build.classes.dir"  value ="${build.dir}/classes"   />

    
<!--  Build classpath  -->
    
< path  id ="build.classpath" >
        
< fileset  dir ="${basedir}/lib" >
            
< include  name ="*.jar"   />
        
</ fileset >
        
< pathelement  location ="${build.classes.dir}"   />
    
</ path >

    
<!--  ===================================================================  -->
    
<!--  Prepares the build directory                                         -->
    
<!--  ===================================================================  -->
    
< target  name ="prepare"  depends ="clean" >
        
< mkdir  dir ="${build.dir}"   />
        
< mkdir  dir ="${build.classes.dir}"   />
    
</ target >

    
<!--  ===================================================================  -->
    
<!--  Compiles the source code                                             -->
    
<!--  ===================================================================  -->
    
< target  name ="compile"  depends ="prepare"  description ="编绎" >
        
< javac  srcdir ="${src.dir}"  destdir ="${build.classes.dir}"  debug ="on"  deprecation ="on"  optimize ="off"  includes ="**" >
            
< classpath  refid ="build.classpath"   />
            
< exclude  name ="junit/**/*.*"   />
        
</ javac >
    
</ target >

    
< target  name ="ejbjar"  depends ="compile"  description ="创建EJB发布包" >
        
< jar  jarfile ="${app.dir}/MDBean.jar" >
            
< fileset  dir ="${build.classes.dir}" >
                
< include  name ="com/**/*.class"   />
            
</ fileset >
            
< metainf  dir ="${src.dir}/META-INF" >
                
< include  name ="**"   />
            
</ metainf >
        
</ jar >
    
</ target >

    
< target  name ="deploy"  depends ="ejbjar" >
        
< copy  file ="${app.dir}/EntityBean.jar"  todir ="${jboss.home}/server/${jboss.server.config}/deploy"   />
    
</ target >

    
<!--  ===================================================================  -->
    
<!--  Cleans up generated stuff                                            -->
    
<!--  ===================================================================  -->
    
< target  name ="clean" >
        
< delete  dir ="${build.dir}"   />
        
< delete  file ="${jboss.home}/server/${jboss.server.config}/deploy/MDBean.jar"   />
    
</ target >

</ project >

 

 最后运行MessageSenderApp.java





 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值