Session Bean Example
@Stateless
1. Create a remote interface
package com.ejb3; /** * @author Clay Zhong - Email: [email protected] * @date Aug 31, 2008 */ public interface HelloWorld { public String sayHello(String name); }
2. Create a local interface
package com.ejb3; /** * @author Clay Zhong - Email: [email protected] * @date Aug 31, 2008 */ public interface HelloWorldLocal extends HelloWorld { public String getInfo(); }
3. Write stateless session bean
package com.ejb3.impl; import com.ejb3.HelloWorld; import com.ejb3.HelloWorldLocal; import javax.ejb.*; import org.jboss.annotation.ejb.RemoteBinding; import org.jboss.annotation.ejb.LocalBinding; /** * Session Bean implementation class HelloWorldBean */ @Stateless @Local( { HelloWorldLocal.class }) @LocalBinding(jndiBinding = "ejbtest/LocalHelloWorld") @Remote( { HelloWorld.class }) @RemoteBinding(jndiBinding = "ejbtest/RemoteHelloWorld") public class HelloWorldBean implements HelloWorld, HelloWorldLocal { public HelloWorldBean() {} /** * @see HelloWorld#sayHello(String) */ public String sayHello(String name) { return "Hello " + name; } @Override public String getInfo() { return "This is local method."; } }
4. Write test class to invoke session bean
import java.util.*; import javax.naming.*; import com.ejb3.HelloWorld; import com.ejb3.HelloWorldLocal; /** * @author Clay Zhong - Email: [email protected] * @date Aug 31, 2008 */ public class EJBTest { public static void main(String[] args) throws NamingException { Properties properties = new Properties(); properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); properties.put(Context.PROVIDER_URL, "jnp://localhost"); InitialContext ctx = new InitialContext(properties); try { HelloWorld helloWorld = (HelloWorld) ctx.lookup("ejbtest/RemoteHelloWorld"); System.out.println(helloWorld.sayHello("Clay")); } catch (Exception e) { System.out.println("Lookup remote class failed."); } try { HelloWorldLocal helloWorldLocal = (HelloWorldLocal) ctx .lookup("ejbtest/LocalHelloWorld"); System.out.println(helloWorldLocal.getInfo()); } catch (Exception e) { System.out.println("Lookup local class failed."); } ctx.close(); } }
@Stateful
1. Create a remote interface
package com.ejb3; /** * @author Clay Zhong - Email: [email protected] * @date Aug 31, 2008 */ public interface HelloWorldRemote { public String sayHello(String name); }
2. Write stateful bean
package com.ejb3.impl; import com.ejb3.HelloWorldRemote; import com.ejb3.HelloWorldLocal; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.*; import org.jboss.annotation.ejb.RemoteBinding; import org.jboss.annotation.ejb.LocalBinding; /** * Session Bean implementation class HelloWorldBean */ @Stateful @Local( { HelloWorldLocal.class }) @LocalBinding(jndiBinding = "ejbtest/LocalHelloWorld") @Remote( { HelloWorldRemote.class }) @RemoteBinding(jndiBinding = "ejbtest/RemoteHelloWorld") public class HelloWorldBean implements HelloWorldRemote, HelloWorldLocal { public HelloWorldBean() {} @Init public void initialize() { // 这个注释指定了有状态session bean初始化的方法。它区别于@PostConstruct注释在于: // 多个@Init注释方法可以同时存在于有状态session bean中, 但每个bean实例只会有一个@Init注释的方法会被调用。 // 这取决于bean是如何创建的. System.out.println("HelloWorld bean initialize..."); } /** * @see HelloWorldRemote#sayHello(String) */ public String sayHello(String name) { return "Hello " + name; } @Override public String getInfo() { return "This is local method."; } @PostConstruct public void Construct() { // 当bean对象完成实例化后,使用了这个注释的方法会被立即调用。 // 这个注释同时适用于有状态和无状态的会话bean。 System.out.println("Construct()方法被调用"); } @PreDestroy public void exit() { // 使用这个注释的方法会在容器从它的对象池中销毁一个无用的或者过期的bean实例之前调用。 // 这个注释同时适用于有状态和无状态的会话bean。 System.out.println("exit()方法被调用"); } @PrePassivate public void serialize() { // 当一个有状态的session bean实例空闲过长的时间, 容器将会钝化(passivate)它,并把它的状态保存在缓存当中。 // 使用这个注释的方法会在容器钝化bean实例之前调用。 这个注释适用于有状态的会话bean。 // 当钝化后,又经过一段时间该bean仍然没有被操作, 容器将会把它从存储介质中删除。 // 以后,任何针对该 bean方法的调用容器都会抛出例外。 System.out.println("serialize()方法被调用"); } @PostActivate public void activate() { // 当客户端再次使用已经被钝化的有状态session bean时, 新的实例被创建, 状态被恢复。 // 使用此注释的session bean会在bean的激活完成时调用。这个注释只适用于有状态的会话bean。 System.out.println("activate()方法被调用"); } @Remove public void stopSession() { // 调用该方法以通知容器移除该 bean 实例、终止会话。方法体可以是空的。 System.out.println("stopSession()方法被调用"); } }
Interceptor
1. Add annotation: @Interceptors({HelloInterceptor.class})
2. Write interceptor class
package com.ejb3.impl; import javax.interceptor.AroundInvoke; import javax.interceptor.InvocationContext; /** * @author Clay Zhong - Email: [email protected] * @date Sep 21, 2008 */ public class HelloInterceptor { @AroundInvoke public Object log(InvocationContext ctx) throws Exception { System.out.println("HelloInterceptor intercepting..."); long start = System.currentTimeMillis(); try { if (ctx.getMethod().getName().equals("sayHello")) { System.out.println("HelloWorld.sayHello() invoked"); } return ctx.proceed(); } catch (Exception e) { throw e; } finally { long time = System.currentTimeMillis() - start; System.out.println("Invoke times: " + time + "ms"); } } }
除了可以在外部定义拦截器之外, 还可以将Session Bean中的一个或多个方法定义为拦截器,如:
@AroundInvoke public Object log(InvocationContext ctx) throws Exception { try { if (ctx.getMethod().getName().equals("sayHello")) { System.out.println("HelloWorld.sayHello() invoked"); } return ctx.proceed(); } catch (Exception e) { throw e; } }
Message Driven Bean
package com.ejb3.impl; import javax.ejb.MessageDriven; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; import javax.ejb.ActivationConfigProperty; /** * @author Clay Zhong - Email: [email protected] * @date Sep 23, 2008 */ @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/fortest") }) public class MDBean implements MessageListener { @Override public void onMessage(Message msg) { try { TextMessage textMessage = (TextMessage) msg; System.out.println("MessageDrivenBean: " + textMessage.getText()); } catch (Exception e) { e.printStackTrace(); } } }
Test Class:
/** * */ import java.util.*; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueSender; import javax.jms.QueueSession; import javax.jms.TextMessage; import javax.naming.*; import com.ejb3.HelloWorldRemote; import com.ejb3.HelloWorldLocal; /** * @author Clay Zhong - Email: [email protected] * @date Aug 31, 2008 */ public class EJBTest { public static void main(String[] args) throws NamingException { Properties properties = new Properties(); properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); properties.put(Context.PROVIDER_URL, "jnp://localhost"); InitialContext ctx = new InitialContext(properties); try { QueueConnectionFactory factory = (QueueConnectionFactory) ctx .lookup("ConnectionFactory"); QueueConnection queueConnection = factory.createQueueConnection(); // 建立不需要事务的并且能自动接收消息收条的会话, 在非事务Session中, 消息传递的方式有三种: // 1. Session.AUTO_ACKNOWLEDGE: 当客户机调用的receive方法成功返回, // 或当MessageListenser成功处理了消息, session将会自动接收消息的收条。 // 2. Session.CLIENT_ACKNOWLEDGE: 客户机通过调用消息的acknowledge方法来接收消息。接收发生在session层。 // 接收到一个被消费的消息时, 将自动接收该session已经消费的所有消息。例如: // 如果消息的消费者消费了10条消息, 然后接收15个被传递的消息, 则前面的10个消息的收据都会在这15个消息中被接收。 // 3. Session.DUPS_ACKNOWLEDGE: 指示session缓慢接收消息。 QueueSession queueSession = queueConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); TextMessage msg = queueSession.createTextMessage("Hi, This is Clay"); QueueSender sender = queueSession.createSender((Queue) ctx.lookup("queue/fortest")); sender.send(msg); queueSession.close(); } catch (Exception e) { System.out.println("Lookup message driven bean failed."); } ctx.close(); } }