Enterprise Java Development@TOPIC@
Add essential EJB aspects to POJO classes
Deploy to server and test
import javax.ejb.Stateless;
...
@Stateless
public class GreeterEJB implements Greeter {
Other types include @Stateful, @Singleton, and @MessageDriven
import javax.ejb.Remote;
...
@Remote
public interface Greeter {
Defines business remote interface for EJB
Alternately can define @Remote(Interface.class) within EJB bean class
@Stateless
@Remote(Greeter.class)
public class GreeterEJB implements Greeter {
public interface Greeter {
String sayHello(String name) throws BadRequestException;
Greeting sayHello(Name name) throws BadRequestException;
}
import javax.ejb.Remote;
@Remote
public interface GreeterRemote extends Greeter {
}
Useful when EJB implements legacy interface
EJB must then implement Remote or declare @Remote
@Stateless
public class GreeterEJB implements GreeterRemote {
@Stateless
@Remote(GreeterRemote.class)
public class GreeterEJB implements Greeter {
Optional callbacks to initialize and destroy resources
@PostConstruct
public void init() {
logger.info("*** GreeterEJB:init({}) ***", super.hashCode());
}
Called after all resources have been injected and before first business method called
No args, void return, no declared checked exceptions
Used to ready bean to satisfy business methods
@PreDestroy
public void destroy() {
logger.info("*** GreeterEJB:destroy({}) ***", super.hashCode());
}
If called, will be after last business method
EJB artifact looks very much like a normal POJO archive
Since our EJB is 100% annotation-based, we have no need for META-INF/ejb-jar.xml descriptor
$ jar tf target/ejb-basic-ejb-4.0.0-SNAPSHOT.jar ... info/ejava/examples/ejb/basic/ejb/BadRequestException.class info/ejava/examples/ejb/basic/ejb/Greeter.class info/ejava/examples/ejb/basic/ejb/GreeterEJB.class info/ejava/examples/ejb/basic/ejb/GreeterRemote.class info/ejava/examples/ejb/basic/dto/Name.class info/ejava/examples/ejb/basic/dto/Greeting.class ...
|-- pom.xml `-- src |-- main | `-- java | `-- info | `-- ejava | `-- examples | `-- ejb | `-- basic | |-- dto | | |-- Greeting.java | | `-- Name.java | `-- ejb | |-- BadRequestException.java | |-- GreeterEJB.java | |-- Greeter.java | `-- GreeterRemote.java `-- test |-- java | `-- info | `-- ejava | `-- examples | `-- ejb | `-- basic | `-- pojo | `-- GreeterTest.java `-- resources `-- log4j.xml
Module contains separate source trees for production and unit test code
EJB module deployed either as naked EJB
17:19:52,979 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named GreeterEJB in deployment unit deployment "ejb-basic-ejb.jar" are as follows: java:global/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote java:app/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote java:module/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote java:jboss/exported/ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote java:global/ejb-basic-ejb/GreeterEJB java:app/ejb-basic-ejb/GreeterEJB java:module/GreeterEJB 17:19:53,012 INFO [org.jboss.weld.deployer] (MSC service thread 1-1) JBAS016005: Starting Services for CDI deployment: ejb-basic-ejb.jar 17:19:53,029 INFO [org.jboss.weld.deployer] (MSC service thread 1-2) JBAS016008: Starting weld service for deployment ejb-basic-ejb.jar 17:19:53,485 INFO [org.jboss.as.server] (DeploymentScanner-threads - 1) JBAS018559: Deployed "ejb-basic-ejb.jar" (runtime-name : "ejb-basic-ejb.jar")
JBoss server prints out JNDI names to access EJB through...
@Remote
No interface
Globally within the server (java:global)
Within the deployed application (java:app)
Within the EJB module (java:module)
External to server (java:global/exported)
Derive remote client JNDI name from "exported" name
ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote
Local and No-interface interfaces are not exposed to remote clients
packaging=ejb
Required in order for downstream containers to recognize as EJB component
javax.ejb:javax.ejb-api
Supplies EJB API definitions
maven-ejb-plugin
Builds EJB and optional ejbclient artifact
<project>
...
<packaging>ejb</packaging>
<dependencies>
...
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<scope>provided</scope>
</dependency>
...
</dependencies>
<build>
<plugins>
<!-- tell EJB plugin to create a client-jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<generateClient>true</generateClient>
<clientExcludes>
<clientExclude>**/ejb/*Local.class</clientExclude>
<clientExclude>**/ejb/*EJB.class</clientExclude>
</clientExcludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Initialized EJB bean instances can be cached in a pool
Instances from the pool can be re-used rather than destroy and re-intialize a new instance
JBoss pools singleton and stateful session beans by default
# standalone/configuration/standalone.xml
<session-bean>
<stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
JBoss defines a stateless session bean pool for use but left unassigned
# standalone/configuration/standalone.xml
<pools>
<bean-instance-pools>
<strict-max-pool name="slsb-strict-max-pool" max-pool-size="20" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
<strict-max-pool name="mdb-strict-max-pool" max-pool-size="20" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
No pooling can be costly when initialization costs are high
Stateless and MDB EJB pooling can be enabled globally
# standalone/configuration/standalone.xml
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name="slsb-strict-max-pool"/>
</stateless>
<stateful default-access-timeout="5000" cache-ref="simple" passivation-disabled-cache-ref="simple"/>
<singleton default-access-timeout="5000"/>
</session-bean>
Pooling can be costly when initialization costs are low
Stateless and MDB EJB pooling can be enabled on a per-application(*)/per-EJB(GreeterEJB) basis
# META-INF/jboss-ejb3.xml
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s="urn:security"
xmlns:c="urn:clustering:1.0"
xmlns:p="urn:ejb-pool:1.0"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd
http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1"
impl-version="2.0">
<assembly-descriptor>
<!-- defines EJB pool else not pooled -->
<p:pool>
<ejb-name>*</ejb-name>
<p:bean-instance-pool-ref>slsb-strict-max-pool</p:bean-instance-pool-ref>
</p:pool>
</assembly-descriptor>
</jboss:ejb-jar>
Added necessary aspects to POJO to make it an EJB
Annotated class as @Stateless
Annotated remote interface as @Remote
Deployed to server
Obtained JNDI name of naked EJB-based @Remote
(component-name)/(ejb-name)!(remote-interface-name)
ejb-basic-ejb/GreeterEJB!info.ejava.examples.ejb.basic.ejb.GreeterRemote