4

我对 GlassFish 和 SAP JCo 连接器 (sapjco3.jar) 有疑问

我在启动 J2EE 应用程序 (jwm.ear) 时加载它,并在第一次需要连接到 SAP 时将其初始化为单例。

问题是这个 jar 始终在内存中初始化,如果我需要更改单个参数,我需要重新启动 glassfish 以卸载初始化的连接。停止或取消部署应用程序不会卸载 sapjco.jar,并且应用程序的进一步重新部署永远不会获得新的连接参数,第一次初始化保持到 GlassFish 重新启动。

有人知道如何卸载或重新初始化这个库吗?最好即使没有重新部署应用程序,第一次激活应用程序时我有对 jcoProvider 的引用,下一次激活会获得对 jcoProvider 的空引用,但 jcoProvider 继续在内存中用初始值实例化。

问候!

注意:GlassFish 在 Windows 2008 服务器中是 2.1 版,jdk 是 1.6.0.14 sapjco3.jar 和 sapjco3.dll 复制到 \domains\domain1\lib\ext 并且是 SAP java 连接器的第 3 版。

单例获取 SAP 连接:

包 es.grupotec.ejb.SAP;

导入 com.sap.conn.jco.JCoDestination;
导入 com.sap.conn.jco.JCoDestinationManager;
导入 com.sap.conn.jco.JCoException;
导入 com.sap.conn.jco.ext.DestinationDataProvider;
导入 com.sap.conn.jco.ext.Environment;
导入 es.grupotec.ejb.util.ConexionSAPException;
导入 java.util.Properties;

公共最终类 SAP {

    私有静态字符串 SAP_SERVER = "JWM";
    私有静态 SAP 实例 = null;
    私有静态 JCOProvider jcoProvider = null;

    私人 SAP() {
      // 仅用于阻止实例化。
    }

    // 获取 SAP 连接
    公共静态同步 JCoDestination getDestination() 抛出 ConexionSAPException {

        JCoDestination jcoDestination = null;

            if (Environment.isDestinationDataProviderRegistered()) {
                尝试 {

                    jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
                    返回 jcoDestination;

                } 捕捉(JCoException ex){

                    抛出新的 ConexionSAPException(ex.getMessage());

                }
            }

        // 创建新连接
        如果(jcoProvider == null)初始化();

        // 获取连接
        尝试 {

            jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
            返回 jcoDestination;

        } 捕捉(JCoException ex){

            抛出新的 ConexionSAPException(ex.getMessage());

        }

    }

    // 初始化与 SAP 的连接
    公共静态同步 void init() 抛出 ConexionSAPException {

        SAPVO sap = 新 SAPVO();
        属性属性 = 新属性();

        如果(jcoProvider == null){


            // 从数据库中获取 SAP 配置
            尝试 {
                sap = SAPDAO.getSAPConfig();
            } 捕捉(异常前){
                抛出新的 ConexionSAPException(ex.getMessage());
            }

             // 创建连接对象
            jcoProvider = 新的 JCOProvider();

        }

        properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
        properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
        properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
        properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
        properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
        properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());

        尝试 {

            jcoProvider.changePropertiesForABAP_AS(属性);

        } 捕捉(异常 e){

            抛出新的 ConexionSAPException(e.getMessage());

        }

    }

    公共静态同步无效更改(SAPVO sap)抛出 ConexionSAPException {

        属性属性 = 新属性();

        // 如果连接为空,则创建一个新的
        if(jcoProvider == null) jcoProvider = new JCOProvider();

        properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
        properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
        properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
        properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
        properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
        properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());

        尝试 {

            jcoProvider.changePropertiesForABAP_AS(属性);

        } 捕捉(异常 e){

            抛出新的 ConexionSAPException(e.getMessage());

        }


    }

    // 防止通过克隆实例化
    @覆盖
    公共对象克隆()抛出 CloneNotSupportedException {

        抛出新的 CloneNotSupportedException();

    }

}

JCo 提供者实现:

包 es.grupotec.ejb.SAP;

导入 com.sap.conn.jco.ext.DestinationDataEventListener;
导入 com.sap.conn.jco.ext.DestinationDataProvider;
导入 com.sap.conn.jco.ext.Environment;
导入 es.grupotec.ejb.util.ConexionSAPException;
导入 java.util.Properties;

公共类 JCOProvider 实现 DestinationDataProvider {

    私有字符串 SAP_SERVER = "JWM";
    私有 DestinationDataEventListener 事件监听器;
    私有属性 ABAP_AS_properties;

    公共 JCOProvider(){

    }

    公共 JCOProvider(SAPVO 树液){

        ABAP_AS_properties = 新属性();
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_ASHOST, sap.getJCO_ASHOST());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_SYSNR, sap.getJCO_SYSNR());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_CLIENT, sap.getJCO_CLIENT());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_USER, sap.getJCO_USER());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_PASSWD, sap.getJCO_PASSWD());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_LANG, sap.getJCO_LANG());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, sap.getJCO_POOL_CAPACITY());
        ABAP_AS_properties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, sap.getJCO_PEAK_LIMIT());

        尝试 {
            if (!Environment.isDestinationDataProviderRegistered())
                Environment.registerDestinationDataProvider(this);
            否则 changePropertiesForABAP_AS(ABAP_AS_properties);
        } 捕捉(异常前){
            字符串味精 = ex.getMessage();
        }

    }

    @覆盖
    公共属性 getDestinationProperties(字符串名称){

        if (name.equals(SAP_SERVER) && ABAP_AS_properties!=null) 返回 ABAP_AS_properties;
        否则返回空值;

    }

    @覆盖
    公共布尔支持事件(){
        返回真;
    }

    @覆盖
    公共无效 setDestinationDataEventListener(DestinationDataEventListener eventListener) {
        this.eventListener = 事件监听器;
    }

 公共无效changePropertiesForABAP_AS(属性属性)抛出ConexionSAPException {

        尝试 {

            if (!Environment.isDestinationDataProviderRegistered()) {

                如果(ABAP_AS_properties == null)ABAP_AS_properties = 属性;
                Environment.registerDestinationDataProvider(this);

            }

            如果(属性 == null){

                if (eventListener != null) eventListener.deleted(SAP_SERVER);
                ABAP_AS_properties = null;

            } 别的 {

                ABAP_AS_properties = 属性;
                if (eventListener != null) eventListener.updated(SAP_SERVER);

            }

        } 捕捉(异常前){

            抛出新的 ConexionSAPException(ex.getMessage());

        }

 }

}

4

2 回答 2

3

您的问题可能与这里涉及​​一些本机代码有关。对于 JCo 3 来说也是如此。尽管 JCo 3 不再使用本地 RFC 库,但它仍然需要 JNI 与 CPIC 层进行通信。

让 JVM 卸载本机库是一项非常令人沮丧的练习。JNI 规范指出,当与它提供实现的类关联的 ClassLoader 被卸载时,本地库将被卸载,但在 JVM 中试图强制 ClassLoader 卸载实际上是不可能的。

如果您的 EAR 文件包含 sapjco3.jar,则每次重新加载代码时都会重新加载它。这很可能会导致异常,因为本机库不能多次加载,并且实际上没有办法卸载本机代码。因此,您可能会考虑将 sapjco3.jar 放在 J2EE 容器之外,让您的 J2EE 引擎在启动时加载该库一次,而不是将其放入反复重新加载的 EAR 中。

于 2009-12-21T19:15:09.660 回答
0

您打算连接到哪个版本的 SAP?Java 连接器有几个问题,它不是真正的线程安全的,并且不能正确地嵌入到 EJB 应用程序中。SAP 的单点登录 seculib 也出现了同样的问题。它要么没有工作。唯一的解决方案是将它加载到 J2EE 引擎之外。

你有没有想过用 webservices 代替 JCO?当然它会稍微慢一些,因为数据必须通过 ICF,但它更健壮。我们将所有集成都切换到了这个解决方案。

于 2009-12-24T00:01:58.370 回答