jboss 是否每次都使用新的InitialContext进行EJB的JNDI查找?

ar5n3qh5  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(164)

我们在我们的应用程序中使用EJB3JBOSS应用服务器。我有一个Bean查找实用程序方法,它是一个通用方法,用于通过JNDI名称查找无状态EJB Bean:

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;
    }

因此,有些类依赖于Bean,它们使用查找方法来调用Bean的方法。

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;
        }

因此,现在当我们对代码运行JProfiler时,lookup方法变得非常耗时,因为每次调用lookup时都会示例化一个新的InitialContext
我在考虑将InitialContext设置为静态的,这样它只在静态块中初始化一次,但我不知道它在获取Bean示例方面会有什么影响。由于这段代码是由EJB容器管理的,运行时的影响是未知的。在网上查找了一些文章后,没有太多的清晰度。
任何帮助都是感激不尽的。

c0vxltue

c0vxltue1#

请注意,InitialContext的javadoc会发出警告:

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.

因此,将字段设置为静态并不一定是个好主意,因为您需要同步每个lookup(jndiName)调用,这可能会导致James R. Perkins注解中的其他问题。
但是,正如您已经展示的,getAuthenticationProfile(String credId)调用lookup两次,没有理由不能让BeanFactory保存一个InitialContext,以便通过在相同的调用方法中重用InitialContext来减少示例的数量。

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;
        }
    }

这允许getAuthenticationProfile使用单个InitialContext进行2次查找:

BeanFactory ctx = BeanFactory.create();
ResourceProceduresDao            dao = ctx.lookup(ResourceProceduresDao.JNDI_NAME);
AuthenticationProfileRemote apRemote = ctx.lookup(AuthenticationProfileRemote.JNDI_NAME);

您还可以考虑将BeanFactory保存为本地线程是否会有所帮助,尽管我非常担心在应用服务器上这样做,因为您可能无法控制哪些线程和多少线程示例化InitialContext,以及它们从什么上下文运行什么。但是,它可能适合在访问EJB服务器逻辑的独立客户端程序中使用:

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);

相关问题