wayne

2008年9月14日 #

JMS (2)

异步队列消息的接收有一点区别,但发送的代码不用改变:

 1@Stateless
 2public class JMSReceiveBean implements JMSReceiveRemote {
 3
 4    @Resource(name = "jms/Queue")
 5    private Queue queue;
 6    @Resource(name = "jms/ConnectionFactory")
 7    private ConnectionFactory queueFactory;
 8
 9    private void receiveJMSMessageFromQueue() throws Exception {
10        Connection connection = null;
11        Session session = null;
12        connection = queueFactory.createConnection();
13        session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
14        MessageConsumer consumer = session.createConsumer(queue);
15        consumer.setMessageListener(new MessageListener() {
16
17            public void onMessage(Message message) {
18                TextMessage msg = (TextMessage) message;
19                try {
20                    String txt = msg.getText();
21                    Logger.getLogger(JMSReceiveBean.class.getName()).log(Level.SEVERE, txt);
22                }
 catch (Exception ex) {
23                    ex.printStackTrace();
24                }

25            }

26        }
);
27        
28        connection.start();
29    }

30
31    public void receiveMessage() {
32        try {
33            receiveJMSMessageFromQueue();
34        }
 catch (Exception ex) {
35            Logger.getLogger(JMSReceiveBean.class.getName()).log(Level.SEVERE, null, ex);
36        }

37    }

38}

在15行消息使用者上设置了一个消息监听器,而没有使用同步的receive方法。由于这是异步接收消息,程序并没有处于阻塞状态,为了避免在接收到消息之前连接终止,所以在28行之后并没有关闭Connection,实际上这一步是不可缺少的。

posted @ 2008-09-14 16:40 waynemao 阅读(103) | 评论 (0)编辑 收藏

JMS (1)

     摘要: 开发任何JMS应用之前,首先要做的事是在应用服务器中配置JMS被管对象:连接工厂和目的地。它们最好不要以编程的方式实现,因为其背后的技术有多种不同的API实现,可能无法移植。以下是glassfish中的配置: 在配置--java消息服务里创建两个物理目的地  名称:myQueue  类型:javax.jms.Queue  名称:myTopic  类...  阅读全文

posted @ 2008-09-14 05:31 waynemao 阅读(296) | 评论 (0)编辑 收藏

2008年9月13日 #

EJB3 (7)

有状态会话bean的开发,首先创建远程接口:

@Remote
public interface HelloRemote {

    String sayHi();

    
void init(String name);
    
    
void remove();
    
}

接着开发有状态会话bean:
@Stateful
public class HelloBean implements HelloRemote {
    
private String name;
    
private Logger log = Logger.getLogger(this.getClass().getName());
    
    
public String sayHi() {
        
return "Hi " + name;
    }


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

    
    @PostConstruct
    
public void postConstrut(){
        log.info(
"create " + this);
    }

    
    @PreDestroy
    
public void preDestory(){
        log.info(
"destory " + this);
    }

    
    @PostActivate
    
public void postActivate(){
        log.info(
"activate " + this);
    }

    
    @PrePassivate
    
public void prePassivate(){
        log.info(
"passivate " + this);
    }

    
    @Remove
    
public void remove(){
        log.info(
"remove " + this);
    }

}

@Stateful注释表明这是一个有状态会话bean,其他的注释是管理会话bean的生命周期。@PostConstruct注释表明方法将会在bean实例化并完成依赖注入后由容器调用此方法;@PreDestory注释表示方法会在容器删除bean实例前由容器调用;以上两个注释所有的EJB(包括MDB)都可以用。@PostActivate注释表示容器在激活bean后调用此方法;@PrePassivate注释表示容器在钝化bean前调用此方法;以上两个注释是有状态会话bean所特有。@Remove注释也是有状态会话bean所特有,也是用户唯一可以能控制的生命周期方法,一旦用户在客户端调用此方法,容器将删除bean实例。接着看客户端的测试代码:
<%
           InitialContext ctx 
= new InitialContext();
           HelloRemote helloBean 
= (HelloRemote)ctx.lookup(HelloRemote.class.getName());
           helloBean.init(
"Tom");
           out.println(helloBean.sayHi());
           helloBean.remove();
%>

很简单,只是多调用了一个remove方法。

posted @ 2008-09-13 11:14 waynemao 阅读(174) | 评论 (0)编辑 收藏

EJB3 (6)

Web服务客户端可以通过bean的Web服务端点实现类来访问无状态会话Bean。在默认情况下,bean类中的所有公共方法对于Web服务客户端都是可访问的。@WebMethod注释可以自定义Web服务方法,一旦在公共方法上使用该注释,那么其他没使用@WebMethod注释的方法将不会对Web服务客户端展现。
首先新建一个EJB模块,然后在EJB模块上新建一个WebService,代码如下:

@WebService()
@Stateless()
public class Dog {
    
    @WebMethod(operationName 
= "ganr")
    
public String ganr() {
        
return "Wo-Wo-Wo";
    }


}

Dog类同时使用了@WebService和@Stateless注释,web服务端点只能是无状态会话bean,web服务本身就是无状态的。我们还用@WebMethod注释向Web服务客户端公开了一个ganr方法,完成后打包部署。
接着我们创建一个Web模块,然后在Web项目上右键,选新建--Web服务客户端,指定项目或者WSDL url。接着新建一个Servlet,然后右键调用Web服务操作,我们找到Dog服务的garn方法点确定,代码自动生成:
@WebServiceRef(wsdlLocation = "http://localhost:8080/DogService/Dog?wsdl")
    
private DogService service;

@WebServiceRef注释声明了一个到Web服务的引用
try // Call Web Service Operation

                ejb.Dog port 
= service.getDogPort();
                
// TODO process result here
                java.lang.String result = port.ganr();
                out.println(
"Result = " + result);
            }
 catch (Exception ex) {
                
// TODO handle custom exceptions here
            }

service.getDogPort()方法获取到服务的一个代理,也称为端口。接着看jsp:
  <%
    
try {
    ejb.DogService service 
= new ejb.DogService();
    ejb.Dog port 
= service.getDogPort();
    
// TODO process result here
    java.lang.String result = port.ganr();
    out.println(
"Result = "+result);
    }
 catch (Exception ex) {
    
// TODO handle custom exceptions here
    }

    
%>

发现只有一点点不同,完成后部署web应用并运行测试。

我们还可以通过一个现有的会话Bean创建Web服务,还是拿HelloWorld举例,首先创建一个远程接口:
@Remote
public interface HelloRemote {

    String sayHi(String name);
}

再创建一个无状态会话bean,先已经说过了,只能是无状态会话bean:
@Stateless
public class HelloBean implements HelloRemote {

    
public String sayHi(String name) {
        
return "Hi " + name; 
    }

}

然后新建一个Web服务Hello,只不过在弹出窗口中要选中“通过现有会话bean创建Web服务”单选框,并浏览指定HelloBean,代码自动完成:
@WebService()
@Stateless()
public class Hello {
    @EJB
    
private HelloRemote ejbRef;
    
// Add business logic below. (Right-click in editor and choose
    
// "Web Service > Add Operation"

    @WebMethod(operationName 
= "sayHi")
    
public String sayHi(@WebParam(name = "name")String name) {
        
return ejbRef.sayHi(name);
    }

}

我们看到Hello服务里引用了一个HelloRemote接口,并发现远程接口公开的方法也被Hello服务公开,完成后打包部署EJB模块。接着在Web服务客户端测试,这和之前的步骤一样,不再赘述,直接看代码吧:
@WebServiceRef(wsdlLocation = "http://localhost:8080/HelloService/Hello?wsdl")
    
private HelloService service;

    
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, IOException {
        response.setContentType(
"text/html;charset=UTF-8");
        PrintWriter out 
= response.getWriter();
        
try {
            
try // Call Web Service Operation

                ejb.Hello port 
= service.getHelloPort();
                
// TODO initialize WS operation arguments here
                java.lang.String name = "Tom";
                
// TODO process result here
                java.lang.String result = port.sayHi(name);
                out.println(
"Result = " + result);
            }
 catch (Exception ex) {
                
// TODO handle custom exceptions here
            }

 

<%
    
try {
    ejb.HelloService service 
= new ejb.HelloService();
    ejb.Hello port 
= service.getHelloPort();
     
// TODO initialize WS operation arguments here
    java.lang.String name = "Tom";
    
// TODO process result here
    java.lang.String result = port.sayHi(name);
    out.println(
"Result = "+result);
    }
 catch (Exception ex) {
    
// TODO handle custom exceptions here
    }

    
%>

发现一个问题,一个应用上不能新建两个Web服务客户端(Dog和Hello),只有一个能有效使用(只找到一份工件),这是为什么?

posted @ 2008-09-13 04:36 waynemao 阅读(128) | 评论 (0)编辑 收藏

WebService (1)

新建web项目,然后创建一个WEB服务:

@WebService()
public class Hello {
    @WebMethod(operationName 
= "sayHi")
    
public String sayHi(@WebParam(name = "name")String name) {
       
return "Hi " + name;
    }

}


可以在源图上右键,选Web服务--添加操作,也可以在设计图上直接添加操作。@WebService标注表明该类是一个web服务,展现给web服务客户端的业务方法必须使用@WebMethod标注来表示。打包部署该web应用,web服务自动会发布。可以在glassfish应用服务器上找到该web服务,直接测试或者查看服务器生成的WSDL

<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.3.1-hudson-417-SNAPSHOT. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.3.1-hudson-417-SNAPSHOT. -->
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webservice/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webservice/" name="HelloService">
    
<types>
        
<xsd:schema>
            
<xsd:import namespace="http://webservice/" schemaLocation="http://localhost:8080/WebServiceApp/HelloService?xsd=1">
            
</xsd:import>
        
</xsd:schema>
    
</types>
    
<message name="sayHi">
        
<part name="parameters" element="tns:sayHi">
        
</part>
    
</message>
    
<message name="sayHiResponse">
        
<part name="parameters" element="tns:sayHiResponse">
        
</part>
    
</message>
    
<portType name="Hello">
        
<operation name="sayHi">
            
<input message="tns:sayHi">
            
</input>
            
<output message="tns:sayHiResponse">
            
</output>
        
</operation>
    
</portType>
    
<binding name="HelloPortBinding" type="tns:Hello">
        
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document">
        
</soap:binding>
        
<operation name="sayHi">
            
<soap:operation soapAction="">
            
</soap:operation>
            
<input>
                
<soap:body use="literal">
                
</soap:body>
            
</input>
            
<output>
                
<soap:body use="literal">
                
</soap:body>
            
</output>
        
</operation>
    
</binding>
    
<service name="HelloService">
        
<port name="HelloPort" binding="tns:HelloPortBinding">
            
<soap:address location="http://localhost:8080/WebServiceApp/HelloService">
            
</soap:address>
        
</port>
    
</service>
</definitions>


也可以编写客户端测试,新建一个普通的java项目,在项目上右键,选择新建--Web服务客户端,在弹出窗口中指定WebService项目或者WSDL url,点击完成。在源代码上右键,选择Web服务客户端资源--调用Web服务操作,在弹出窗口中选择sayHi操作,点确定,测试代码自动生成:

public class Main {

    
public static void main(String[] args) {

        
try 

            webservice.HelloService service 
= new webservice.HelloService();
            webservice.Hello port 
= service.getHelloPort();
            
            java.lang.String name 
= "Tom";
            java.lang.String result 
= port.sayHi(name);
            System.out.println(
"Result = " + result);
        }
 catch (Exception ex) {
            
// TODO handle custom exceptions here
        }

    }

}

运行该客户端,结果将会输出

posted @ 2008-09-13 02:31 waynemao 阅读(148) | 评论 (0)编辑 收藏

oracle视频

oracle10g_1

oracle10g_2

oracle10g_3_1

oracle10g_3_2

oracle10g_4_1

oracle10g_4_2

oracle10g_5_1

oracle10g_5_2

oracle10g_6

oracle10g_7_1

oracle10g_7_2

oracle10g_8

oracle10g_9

oracle10g_10

oracle10g_11

oracle10g_12

oracle10g_13

oracle10g_14

posted @ 2008-09-13 01:01 waynemao 阅读(148) | 评论 (0)编辑 收藏

EJB3 (5)

同一个会话bean也可以实现多个远程接口,不过代码上有些地方要注意,首先写第一个接口:

@Remote
public interface HelloRemote {

    String sayHi(String name);
}

第二个接口:
@Remote
public interface HelloRemote1 {
    
    String sayBye(String name);
}

接下来写会话bean,同时实现以上两个接口:
@Stateless(mappedName="hello")
public class HelloBean implements HelloRemote, HelloRemote1 {

    
public String sayHi(String name) {
        
return "Hi " + name; 
    }


    
public String sayBye(String name) {
        
return "Bye " + name;
    }
    
}

注意这里用到了mappedName元素,这个很关键。把EJB模块打包部署,接下来在远程客户端测试,先写Servlet:
    @EJB(mappedName="hello#ejb.HelloRemote1")
    
private HelloRemote1 helloBean1;
    @EJB(mappedName
="hello#ejb.HelloRemote")
    
private HelloRemote helloBean;

注意@EJB标注里也使用了mappedName元素,值的样式是:JNDI名#包名.接口名。再看Jsp:
<%
            InitialContext ctx 
= new InitialContext();
            HelloRemote helloBean 
= (HelloRemote)ctx.lookup("hello#ejb.HelloRemote");
            out.println(helloBean.sayHi(
"Tom"));
            HelloRemote1 helloBean1 
= (HelloRemote1)ctx.lookup("hello#ejb.HelloRemote1");
            out.println(
"<br>" + helloBean1.sayBye("Tom"));
%>

和Servlet中的一样

posted @ 2008-09-13 00:42 waynemao 阅读(126) | 评论 (0)编辑 收藏

EJB3 (4)

如果一个远程接口有两个实现,需要用mappedName来区分
首先定义一个远程接口:

@Remote
public interface HelloRemote {

    String sayHi(String name);
}


第一个实现:
@Stateless(mappedName="hello")
public class HelloBean implements HelloRemote {

    
public String sayHi(String name) {
        
return "Hi " + name; 
    }

}

第二个实现:
@Stateless(mappedName="hello2")
public class HelloBean2 implements HelloRemote{

    
public String sayHi(String name) {
        
return "Hello " + name;
    }


}

两个无状态会话bean实现了同一个远程接口,但它们的mappedName不一样,还有它们各自重写了sayHi业务方法。部署EJB模块然后测试,首先是Servlet:
    @EJB(mappedName="hello2")
    
private HelloRemote helloBean2;
    @EJB(mappedName
="hello")
    
private HelloRemote helloBean;

然后是JSP:
<%
            InitialContext ctx 
= new InitialContext();
            HelloRemote helloBean 
= (HelloRemote)ctx.lookup("hello");
            out.println(helloBean.sayHi(
"Tom"));
            HelloRemote helloBean2 
= (HelloRemote)ctx.lookup("hello2");
            out.println(
"<br>" + helloBean2.sayHi("Tom"));
%>

呵呵,远程调用也实现了多态

posted @ 2008-09-13 00:21 waynemao 阅读(153) | 评论 (0)编辑 收藏

2008年9月12日 #

EJB3 - Session bean

EJB3 - Session bean

description

其實session bean是最一開始就看的, 回過頭來看再記重點有點心浮氣躁.

reference

EJB3 in Action - CH3 - Building business logic with session beans

Focal Points

  • session bean一定要有一個以上的interface與一個實現
  • 一個session bean可以有多個interface, 所以當客戶端調用一個@Local的interface, 就是使用local的session bean. 使用@Remote或@WebService就是用remote或web service的session bean.
  • session bean一定要是concrete class, 一定要有無參构造函数, 不能是abstract或final.
  • session bean可以是其他session bean或POJO的subclass.
  • session bean的business method與lifecycle callback可定在super class或session bean class裡.
  • session bean的annotation的繼承是有條件的, 就是class level比方說@Stateless, @Stateful會被忽略, 不過lifecycle callback會被繼承下來.
  • session bean的business method name不能以ejb開頭, 比方說不能是ejbDoit()
  • session bean的method必須是public且不能是static或final
  • 使用一個remote business interface要注意argument與return type必須實作Serizable
  • 所有session bean都有的生命週期是creation / destruction
  • stateful bean比stateless bean又多了passivation / activation
  • stateless bean的lifecycle callback為@PostConstruct, @PreDestroy
  • stateful bean的lifecycle callback為@PostConstruct, @PreDestroy, @PostActivate, @PrePassivate
  • @PostConstruct, @PreDestroy比較簡單.就是container实例化session bean後调用@PostContruct, container移除session bean前會调用@PreDestroy
  • @PostActivate, @PrePassivate比較特別.  一旦container判斷一個stateful bean停用了而決定要暫時讓這個session bean失去效用, 這個動作叫钝化. 而container讓已經失效的stateful bean再度生效就叫激活. 所以@PostActivate就是activation後调用的method, @PrePassivate就是钝化前呼叫的method.
  • lifecycle callback可以是public, private, protected, package-protected
  • lifecycle callback主要用來替session bean準備实例化後需要的資源以及從container移除前要釋放的資源.
  • lifecycle callback除了放在session bean以外也可放在分開的interceptor class
  • stateless session bean有pool, 也就是說有一定數量的stateless session bean在container的pool中
  • @Stateless的定義
    1. 屬性有name, mappedName, description
    2. name屬性用來指定bean的name, 有的container用來和JNDI綁定. 如果name沒有設定就會是bean的class name.
    3. mappedName是vender-specific(特定于厂商), 也就是依不同container有不同的情形. 以GlassFish來說是將mappedName的值綁定到JNDI name.
  • @Local: stateless session bean的local interface, local interface表示這個session bean和client放在同一個JVM上執行.
  • @Remote: 當client存在於container外的JVM時就必須使用@Remote
    1. 一個@Remote interface可以繼承java.rmi.Remote
       public interface TestRemote extends Remote { ... } 
      就算程序裡面沒寫繼承Remote, container還是會在byte code階段插入繼承Remote的動作
    2. 沒有程序上繼承java.rmi.Remote的好處就是不用處理java.rmi.RemoteException
    3. @Remote business interface有個需求就是所有的參數與回傳值都必須是Serializable, 因為這樣才能通過RMI
  • @WebService: 透過@WebService可讓session bean成為SOAP-based web service. 唯一要做的就是在interface上加上@WebService.
  • 不能讓一個business interface同時@Local又@Remote或是又@WebService, 不過可以透過interface的繼承改變要使用的是@Remote session bean還是@Local的 session bean.
  • 放session bean的lifecycle callback
  • 可以有多個@PostConstruct, @PreDestroy (不過我試起來一個session bean就只能一個lifecycle callback有效, 頂多除了callback以外還指定interceptor, 就加上interceptor的一個lifecycle callback有效.)
  • lifecycle callback要符合pattern: void < METHOD >()
  • interceptor內的lifecycle callback要符合pattern: Object < METHOD >(InvocationContext) throws Exception, 然後記得回傳InvocationContext.proceed, 除非打算不繼續執行. (可參考EJB3 Interceptor)
  • session bean的lifecycle callback不可有checked exception, interceptor的則可以.
  • session bean的lifecycle callback不可有傳入參數, interceptor則要傳入InvocationContext, 否則有java.lang.IllegalArgumentException: wrong number of arguments
  • stateless session bean與stateful session bean的差別主要在於container管理的方式, stateless session bean起始之後會被container放進pool, 等client要使用的時候再從pool取出, 用完再放回pool. stateful session bean則是讓一個client擁有一個stateful session bean直到client離開或stateful session bean destroy為止. stateful session bean與client是one to one的關係.
  • stateful session bean需要付出代價, stateless session bean由於所有client共用session bean比較能節省資源, stateful session bean則因為與client是one to one的關係所以比較耗資源. 一旦container判斷消耗資源太多或佔用資源太久就會開始執行passivate的動作.
  • 由於stateful session bean比較耗資源, 所以注意要在stateful session bean加上@Remove method, 當呼叫此method, container就會負責將此method destroy以節省資源.
  • 由於stateful session bean在passivate的時候會做serialize的動作, 所以注意stateful session bean的class 成员必須實做Serializable或必須是原始类型. 否則在passivate的時候會出現例如[NRU-stateful.SimpleStatefulBean]: passivateEJB(), Exception caught 的exception, 就是因為無法serialize該object的關係. 如果要使用不須serialize的class 成员只要用transient声明該class member或在@PrePassivate把class member改成null再於@PostActivate設定回來即可.
  • 使用stateful session bean的方式幾乎和stateless session bean的方式幾乎一樣, 唯一不一樣的是stateful session bean的business interface只能使用@Local與@Remote而不能用@WebService. 因為SOAP-based web Service本來就不是stateful因此無法使用.
  • stateful session bean的生命週期中有重要的一點就是container在destroy一個passivate的時候會先將該stateful session bean先activate再passivate.
    @Stateful(name="SimpleStatefulBean", mappedName="ejb/SimpleStatefulBean")
    public class SimpleStatefulBean implements SimpleStatefulRemote {
    private Logger logger = Logger.getLogger("SimpleStatefulBean");
    private byte[] b = new byte[100000];
    {
    for ( int i = 0; i < b.length; i++ ) {
    b[i] = (byte) 100;
    }
    }
    public String simpleShow() {
    return this + ":This is simple show" + b;
    }
    @PostConstruct
    public void postConstruct() {
    logger.info("create " + this);
    }
    @PreDestroy
    public void preDestroy() {
    logger.info("destroy " + this);
    }
    @PostActivate
    public void postActivate() {
    logger.info("activate " + this);
    }
    @PrePassivate
    public void prePassivate() {
    logger.info("passivate " + this);
    }
    @Remove
    public void remove() {
    logger.info("remove " + this);
    }
    }
    
    放interceptor的lifecycle callback
    @Stateless
    @Interceptors(value={SimpleInterceptor.class})
    public class SimpleStatelessBean implements SimpleStatelessLocal {
    private Logger logger = Logger.getLogger("SimpleStatelessBean");
    @Resource(name="TestQueueConnectionFactory")
    private ConnectionFactory connectionFactory;
    @Resource(name="jms/TestQueueDestination")
    private Destination destination;
    public String simpleShow() {
    try {
    Connection conn = connectionFactory.createConnection();
    Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
    MessageProducer messageProducer = session.createProducer(destination);
    TextMessage message = session.createTextMessage();
    message.setText("This is text message");
    messageProducer.send(message);
    messageProducer.close();
    session.close();
    conn.close();
    } catch (JMSException ex) {
    throw new RuntimeException( ex );
    }
    return this + ":This is simple show";
    }
    }
    public class SimpleInterceptor {
    Logger logger = Logger.getLogger("SimpleStatefulBeanInterceptor");
    @PostConstruct
    public void onCreate(InvocationContext ic) {
    try {
    logger.info("create " + this);
    ic.proceed();
    } catch (Exception ex) {
    Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    @AroundInvoke
    public Object aroundInvoke(InvocationContext ctx) throws Exception {
    logger.info(ctx + " is invoked.");
    return ctx.proceed();
    }
    @PreDestroy
    public void onDestroy(InvocationContext ic) {
    try {
    logger.info("destroy " + this);
    ic.proceed();
    } catch (Exception ex) {
    Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
    }
    
    stateful bean的@PrePassivate, @PostActivate也可放interceptor
    @Interceptors(value={SimpleInterceptor.class})
    @Stateful(name="SimpleStatefulBean", mappedName="ejb/SimpleStatefulBean") public class SimpleStatefulBean implements SimpleStatefulRemote { private byte[] b = new byte[100000]; { for ( int i = 0; i < b.length; i++ ) { b[i] = (byte) 100; } } public String simpleShow() { return this + ":This is simple show" + b; } @Remove public void remove() { Logger.getLogger("SimpleStatefulBean").info("remove " + this); } } public class SimpleInterceptor { @PostConstruct public void onCreate(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("create " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } @PostActivate public void onActivate(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("activate " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } @PrePassivate public void onPassivate(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("passivate " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } @AroundInvoke public Object aroundInvoke(InvocationContext ctx) throws Exception { Logger.getLogger(SimpleInterceptor.class.getName()).info(ctx + " is invoked."); return ctx.proceed(); } @PreDestroy public void onDestroy(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("destroy " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } }
  • @EJB用來注入session bean到client code. @EJB有幾個屬性: name, beanInterface, beanName. name用來指定JNDI name, beanName則是當一個interface有兩個實作時用來決定要注入哪個實作.
  • 使用@EJB注入的時候如果沒有指定JNDI name, container就會用interface name當成JNDI name注入.
  • 如果要注入同個interface不同的實作可透過指定JNDI name或beanName
    @Stateless(name="SimpleStatelessBean1")
    public class SimpleStatelessBean1 implements SimpleStatelessLocal { ... }
    @Stateless(name="SimpleStatelessBean2")
    public class SimpleStatelessBean2 implements SimpleStatelessLocal { ... }
    public class SimpleStatelessServlet extends HttpServlet {
    @EJB(beanName="SimpleStatelessBean1")
    private SimpleStatelessLocal simpleStatelessLocal1;
    @EJB(beanName="SimpleStatelessBean2")
    private SimpleStatelessLocal simpleStatelessLocal2;
    ...
    }
    
  • 可注入stateless bean或stateful bean到其他的stateful bean. 但不能注入stateful bean到stateless bean, 因為這樣stateful session bean就會被所有client分享.
  • 注入stateful bean到另一個stateful bean時, 一旦持有注入的stateful bean destroy了, 被持有的stateful bean也會一起destroy.
  • 如果不用stateful bean可將狀態放在DB中或放在server side的檔案或放HttpSession, 不過要注意清除不必要的資源.
  • 儲存conversation state的時候要注意儲存的值愈小愈好, 例如primitive.
  • stateful bean要記得定義@Remove method.
  • 調整server到stateful bean效能最佳的狀態, 小心頻繁的passivate / activate造成效能變差太多.
  • posted @ 2008-09-12 23:19 waynemao| 编辑 收藏

    EJB3 (3)

    我想在远程对象中调用本地对象,我尝试这样编写代码,首先创建一个本地接口:
    @Local
    public interface MessageLocal {

        String getMessage();
        
    }

    接着编写一个会话bean实现该接口:
    @Stateless
    public class MessageBean implements MessageLocal {

        
    public String getMessage() {
            
    return "Hello world";
        }

        
    }

    然后创建一个远程接口:

    @Remote
    public interface HelloRemote {

        String welcome();
        
    }

    编写一个会话bean实现该接口:
    @Stateless
    public class HelloBean implements HelloRemote {
        @EJB
        
    private MessageLocal messageBean;

        
    public String welcome() {
            
    return messageBean.getMessage();
        }

        
    }

    在远程对象里声明了一个本地接口的引用,并尝试在远程方法当中调用本地接口的本地方法。这些都没问题,打包部署成功。
    <%
                InitialContext ctx 
    = new InitialContext();
                HelloRemote helloBean 
    = (HelloRemote)ctx.lookup(HelloRemote.class.getName());
                out.println(helloBean.welcome());
    %>

    在远程客户端的代码如此,看起来一切正常,不过在部署WEB模块的时候报异常:正在域中部署应用程序 失败;为模块 [EjbWebClient] 装入部署描述符时出错 -- Cannot resolve reference Unresolved Ejb-Ref ejb.HelloBean/messageBean@jndi: @null@ejb.MessageLocal@Session@null

    posted @ 2008-09-12 22:24 waynemao 阅读(217) | 评论 (0)编辑 收藏

    仅列出标题  下一页

    My Links

    Blog Stats

    常用链接

    留言簿(1)

    随笔分类

    随笔档案

    default

    搜索

    最新评论

    阅读排行榜

    评论排行榜