We use EJB3
and JBOSS
application Server in our Application. I have a Bean lookup utility method where its a generic method written to lookup stateless EJB Beans by JNDI name:
public class BeanFactory {
static Logger logger = LogManager.getLogger(BeanFactory.class.getName());
/**
*
* @param jndiName
* @return
*/
public static <T> T lookup(String jndiName){
logger.info("Inside bean BeanFactory lookup: " + jndiName);
T handle = null;
try {
InitialContext ctx = new InitialContext();
handle = (T) ctx.lookup(jndiName);
} catch (Exception e) {
logger.error(e, e.fillInStackTrace());
}
return handle;
}
So there are classes which have dependencies on Beans and they use lookup method to invoke the methods of the Bean. For Example
private AuthenticationProfileDTO getAuthenticationProfile(String credId) throws OneM2MException {
ResourceProceduresDao dao = BeanFactory.lookup(ResourceProceduresDao.JNDI_NAME);
AuthenticationProfileRemote apRemote = BeanFactory.lookup(AuthenticationProfileRemote.JNDI_NAME);
AuthenticationProfileDTO authenticationProfileDTO;
if (isKpsaId(credId))
authenticationProfileDTO = apRemote.getAuthenticationProfileDTOForSymmKeyID(credId);
else
authenticationProfileDTO = apRemote.getAuthenticationProfileDTOForCredentialID(credId);
return authenticationProfileDTO;
}
So now when we ran JProfiler on the code the lookup
method is coming to be time consuming because every time lookup
is called a new InitialContext
is instantiated.
I was thinking of making the InitialContext static so that only once it's initialized in a static block, but I don't know what implications will it have in terms of getting Bean instances. Since this piece of code is managed by EJB Container, the run time impacts are unknown. After looking up some articles online not much clarity was there.
Any help is appreciated.
Note that javadoc for InitialContext
warns that:
An InitialContext instance is not synchronized against concurrent
access by multiple threads. Multiple threads each manipulating a
different InitialContext instance need not synchronize.
Threads that need to access a single InitialContext instance
concurrently should synchronize amongst themselves and provide the
necessary locking.
So, making the field static isn't necessarily a good idea as you'll need to synchronize each lookup(jndiName)
call, and this may cause other issues as per comment by James R. Perkins
.
However as you have shown that getAuthenticationProfile(String credId)
calls lookup
twice, there is no reason why you can't make a BeanFactory
hold one InitialContext
to reduce the number of instances by re-using InitialContext
within same calling methods.
public class BeanFactory {
private final InitialContext ctx;
private BeanFactory(InitialContext initialContext) {
this.ctx = initialContext;
}
private static final Logger logger = LogManager.getLogger(BeanFactory.class.getName());
/** JNDI lookup*/
public <T> T lookup(String jndiName){
// logger.info("Inside bean BeanFactory lookup: " + jndiName);
try {
return (T) ctx.lookup(jndiName);
} catch (Exception e) {
RuntimeException re = new RuntimeException("Could not find jndi: "+jndiName, e);
logger.error(re);
throw re;
}
}
/** Setup a new BeanFactory */
public static BeanFactory create() {
try {
return new BeanFactory(new InitialContext());
} catch (Exception e) {
throw new RuntimeException("Could not create a new context", e);
logger.error(re);
throw re;
}
}
This allows getAuthenticationProfile
to use a single InitialContext
for 2 lookups:
BeanFactory ctx = BeanFactory.create();
ResourceProceduresDao dao = ctx.lookup(ResourceProceduresDao.JNDI_NAME);
AuthenticationProfileRemote apRemote = ctx.lookup(AuthenticationProfileRemote.JNDI_NAME);
You might also consider whether saving BeanFactory
as a thread local would help though I would be very concerned about doing this an application server because you may have little control over which and how many threads instantiate InitialContext
and what from what context they run. However it might be suitable within a standalone client program accessing your EJB server logic:
private static final ThreadLocal<BeanFactory> BEANS = ThreadLocal.withInitial(BeanFactory::create);
private static BeanFactory local() {
return BEANS.get();
}
// Example lookups:
ResourceProceduresDao dao = BeanFactory.local().lookup(ResourceProceduresDao.JNDI_NAME);
AuthenticationProfileRemote apRemote = BeanFactory.local().lookup(AuthenticationProfileRemote.JNDI_NAME);