====== Creating ======
Creating EJBs is easy. Simply create a class with the appropriate annotations and deploy it as part of a .war or .jar.
===== Singleton EJB =====
Singletons can be useful, especially when you have big/costly resources (which probably need to be initialized at deployment, not when they are first needed). To do this add the @Singleton annotation to your class. If you want to do some initialization also add the @Startup annotation and a method annotated with @PostConstruct
Example
@Startup
@Singleton
@Lock(LockType.WRITE) // If you are unsure if your class is threadsafe, add this to forbid concurrent access.
public class RMMMapmatcher implements Mapmatcher {
@PostConstruct
private void init() {
//some initialization stuff
}
public String doSomething() {
return "something";
}
}
===== Remotely accessible EJB =====
Please note that 'remote' here does not only necessarily mean "remote server" but rather anything that is not in the same application (and thus has a different classloader / different class visibilities). Generally remote access can be achieved by using the @Remote annotation. However things are bit more complicated when you want to cast the bean to a usable class (JNDI lookup returns java.lang.Object):
*1.) create a bean-api.jar which defines the API of the EJB
* bean-api.jar should contain the interface of the EJB and all data transfer classes
* all data transfer classes need to be Serializable
* the bean-api.jar will be a dependency for the EJB implementation and the EJB user
* --> the .jar must not contain the actual EJB implementation/annotations, otherwise it will be deployed multiple times (which is probably not what you want)
*2.) implement the EJB in a separate .jar or .war and add the appropriate @Remote annotation:
@Startup
@Singleton
@Remote(Mapmatcher.class) // interface from the bean-api.jar
public class RMMMapmatcher implements Mapmatcher {
// implementation
}
*3.) implement the JNDI EJB lookup on the client
Object o = new InitialContext().lookup("java:global/map-service/RMMMapmatcher"); // JNDI lookup
Mapmatcher mm = (Mapmatcher) o; // cast to interface of bean-api.jar
// use normally ..
====== Using ======
There are several ways of using the EJB:
* When you are inside a container managed class you can just use dependency injection (see [[Java CDI]]).
* Anywhere else you can use JNDI to get a reference to to the class:
===== Lookup via JNDI =====
When the EJB is being deployed JBoss shows under which JNDI names it is registered. It should look something like this:
13:01:08,136 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-1) JNDI bindings for session bean named
DefaultTraveltimeService in deployment unit deployment "traveltime-service.war" are as follows:
java:global/traveltime-service/DefaultTraveltimeService
java:app/traveltime-service/DefaultTraveltimeService
java:module/DefaultTraveltimeService
Knowing this name, using the EJB is straingtforward:
DefaultTraveltimeService s = (DefaultTraveltimeService) new InitialContext().lookup("java:global/traveltime-service/DefaultTraveltimeService");
Note that JBoss registers the EJB under several names which are visible to different contexts:
* **java:global** - visible to the whole application server (other .wars and .ejbs) \\ Please note that just being "visible" does not imply that it is actually _usable_ without further steps. Have a look at [[JBoss EJB#Remotely accessible EJB]].
* **java:app** - visible in the same application
* **java:module** - visible in the same module
see https://docs.jboss.org/author/display/AS71/JNDI+Reference for details
==== Additional Global JNDI names ====
The @EJB anntation can be used to register an EJB under addtional JNDI names:
@Stateless
@EJB(name = "java:global/MyBean", beanInterface = MyBean.class)
public class MyBean
{
}
However comining this technique with @Remote currently breaks the JNDI page in the JBoss 7.1.1 administration console.