使用 Spring 通过 Grails 访问 WebSphere 中的跨集群 EJB

发布于 2024-09-08 09:26:02 字数 2013 浏览 4 评论 0原文

最近几天我一直在尝试将 Grails(版本 1.3.2)应用程序与部署在 WebSphere 6.1 上的 EJB 2.1 应用程序集成。一旦我们的 Grails 应用程序投入生产,它们也将部署到 WebSphere。 EJB 2.1 应用程序在我们公司范围内广泛使用,并且在除本地开发环境之外的任何环境中都部署到其自己的集群中。我们在现有的 Java EE 应用程序(所有这些应用程序都是非 Spring、非 Grails)中处理此问题的方法是在每个其他集群中绑定 CORBA CosNaming 命名上下文,然后可以使用该上下文来获取对共享 EJB 的引用2.1 应用。 ,到目前为止,如果我们的某个应用程序需要与此应用程序交互,他们将使用如下方法来实现:

String cosNameBinding = "ejbApp.HighAvail.cluster";
InitialContext initial = new InitialContext();
Context fedContext = (javax.naming.Context) initialCtx.lookup(cosNameBinding);

然后使用 federated/CosNaming 上下文执行正常的 EJB 样式查找/缩小/调用:

Object ejbHomeAsObject = fedContext.lookup(jndiNameOfService);        
EJBHome home = (EJBHome) PortableRemoteObject.narrow(ejbHomeAsObject, homeClass);
Object service = invokeMethod(homeClass, home, "create");

因此 可以看到,这里发生了一定程度的间接,以便从 InitialContext 转到可用于与共享 EJB 应用程序交互的联合命名上下文。

在本地运行,我将 Grails 应用程序和 EJB 应用程序部署到同一服务器(非网络部署 WAS,相同的配置文件和节点)。我已经像这样配置了 Spring:

beans = {
        ejbJndi(org.springframework.jndi.JndiTemplate) {
            environment = ["java.naming.factory.initial" : 
                           "com.ibm.websphere.naming.WsnInitialContextFactory"]
        }
        crewMemberService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
            jndiName="hotelService/ejb/HotelService"
            businessInterface="com.company.appName.hotel.HotelService"
            lookupHomeOnStartup="false"
            cacheHome="false"
            refreshHomeOnConnectFailure="true"
            jndiTemplate = ref("ejbJndi")
        }
}

我可以成功地将 ejb 引用注入到我的 Grails 控制器中并调用它们。但是,WebSphere 只能解析 JNDI 查找,因为它们都部署在同一服务器上。当我们将其移动到我们的开发环境之一时,我们需要对这些服务进行 jndi 查找,以对抗联合命名上下文。

所以我的问题是:

  1. 有没有办法用 Spring 中提供的类来做到这一点,如果可以的话,你能给我一个关于我需要如何修改 Spring 配置来做到这一点的想法吗?
  2. 鉴于我们如何部署其他应用程序或获取对其服务的引用(我们必须使用联合上下文)没有灵活性,我是否应该考虑扩展 JndiTemplate 并自己进行必要的连接?

如果有人遇到过这种情况,我将非常感谢您能够提供的任何见解。

I have spent the last few days attempting to integrate a Grails (version 1.3.2) application with an EJB 2.1 application that is deployed on WebSphere 6.1. Once our grails apps are in production, they will be deployed to WebSphere as well. The EJB 2.1 application is widely used across our company and, in anything except a local development environment, is deployed to its own cluster. The way we handle this in our existing Java EE applications (all of which are non-Spring, non-Grails) is to bind a CORBA CosNaming Naming Context within each of our other clusters that can then be used to obtain references to our shared EJB 2.1 application. So, up to this point, if one of our application needed to interact with this application, they would do so using an approach like this:

String cosNameBinding = "ejbApp.HighAvail.cluster";
InitialContext initial = new InitialContext();
Context fedContext = (javax.naming.Context) initialCtx.lookup(cosNameBinding);

Then do the normal EJB-style lookup/narrow/invoke using the federated/CosNaming context:

Object ejbHomeAsObject = fedContext.lookup(jndiNameOfService);        
EJBHome home = (EJBHome) PortableRemoteObject.narrow(ejbHomeAsObject, homeClass);
Object service = invokeMethod(homeClass, home, "create");

As you can see, there is a level of indirection that occurs here in order to go from the InitialContext to the federated naming Context that can be used to interact with the shared EJB application.

Running locally, I have both the Grails application and the EJB application deployed to the same server (non network deployment WAS, same profile&node). I have Spring configured like so:

beans = {
        ejbJndi(org.springframework.jndi.JndiTemplate) {
            environment = ["java.naming.factory.initial" : 
                           "com.ibm.websphere.naming.WsnInitialContextFactory"]
        }
        crewMemberService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
            jndiName="hotelService/ejb/HotelService"
            businessInterface="com.company.appName.hotel.HotelService"
            lookupHomeOnStartup="false"
            cacheHome="false"
            refreshHomeOnConnectFailure="true"
            jndiTemplate = ref("ejbJndi")
        }
}

And I can successfully inject ejb references into my Grails controllers and invoke them. However, WebSphere can only resolve the JNDI lookup because they are both deployed on the same server. When we move it to one of our development environments, we'll need jndi lookups for these services to go against the federated naming context.

So my questions are:

  1. Is there a way to do this with the classes that are provided within Spring and if so could you give me an idea of how I would need up modify my Spring config to do so?
  2. Given that there is no flexibility around how we deploy the other app or gain references to its services (we must use the federated context), should I consider extending JndiTemplate and do the necessary wiring myself?

If anyone has faced this situation I would be most appreciative for any insights you may be able to offer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

这样的小城市 2024-09-15 09:26:04

如果有人以后有同样的问题,我最终实现了 Spring 的 JndiTemplate 的扩展并使用它。这是代码:

public class FederatedJndiTemplate extends org.springframework.jndi.JndiTemplate
{
    protected static final String JNDI_CONTEXT_BINDING_NAME = "fed.context.jndiName";

    /**
     * Obtain a JNDI naming context for the specified federated naming context.
     * 
     * @throws NamingException if no "fed.context.jndiName" has been specified in
     * the environment properties for the jndiTemplate or the container throws a naming
     * exception.
     */
    @Override
    protected Context createInitialContext() throws NamingException {
        Properties props = super.getEnvironment();

        if(!props.containsKey(JNDI_CONTEXT_BINDING_NAME)) {
            throw new NamingException("You must specify the federated naming context JNDI binding name");
        }

        String jndiBinding = props.getProperty(JNDI_CONTEXT_BINDING_NAME);
        InitialContext initCtx = new InitialContext();
        Context fedCtx = (Context) initCtx.lookup(jndiBinding);
        return fedCtx;
    }
}

然后在我的 resources.groovy 中,我刚刚使用了这个 JndiTemplate:

            ejbJndi(com.myCompany.spring.jndi.FederatedJndiTemplate) {
                    environment = [
                        "fed.context.jndiName":"myServices.HighAvail.Cluster"]
            }
            hotelService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
                jndiName="hotelService/ejb/HotelService"
                businessInterface="com.mycompany.appName.hotel.HotelService"
                homeInterface="com.mycompany.appName.hotel.HotelServiceHome"
                lookupHomeOnStartup="false"
                jndiTemplate = ref("ejbJndi")
            }

In case anyone has this same question down the road, I ended up implementing an extension to Spring's JndiTemplate and using that. Here is the code:

public class FederatedJndiTemplate extends org.springframework.jndi.JndiTemplate
{
    protected static final String JNDI_CONTEXT_BINDING_NAME = "fed.context.jndiName";

    /**
     * Obtain a JNDI naming context for the specified federated naming context.
     * 
     * @throws NamingException if no "fed.context.jndiName" has been specified in
     * the environment properties for the jndiTemplate or the container throws a naming
     * exception.
     */
    @Override
    protected Context createInitialContext() throws NamingException {
        Properties props = super.getEnvironment();

        if(!props.containsKey(JNDI_CONTEXT_BINDING_NAME)) {
            throw new NamingException("You must specify the federated naming context JNDI binding name");
        }

        String jndiBinding = props.getProperty(JNDI_CONTEXT_BINDING_NAME);
        InitialContext initCtx = new InitialContext();
        Context fedCtx = (Context) initCtx.lookup(jndiBinding);
        return fedCtx;
    }
}

Then inside my resources.groovy, I just used this JndiTemplate:

            ejbJndi(com.myCompany.spring.jndi.FederatedJndiTemplate) {
                    environment = [
                        "fed.context.jndiName":"myServices.HighAvail.Cluster"]
            }
            hotelService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
                jndiName="hotelService/ejb/HotelService"
                businessInterface="com.mycompany.appName.hotel.HotelService"
                homeInterface="com.mycompany.appName.hotel.HotelServiceHome"
                lookupHomeOnStartup="false"
                jndiTemplate = ref("ejbJndi")
            }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文