java - SAP JCo 连接器在 GlassFish v2.1 中永久加载(无法卸载)

标签 java jakarta-ee glassfish sapjco3

我在使用 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 连接:

package es.grupotec.ejb.SAP;

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

public final class SAP {

    private static String SAP_SERVER = "JWM";
    private static SAP instance = null;
    private static JCOProvider jcoProvider = null;

    private SAP() {
      // Exists only to defeat instantiation.
    }

    // Get SAP connection
    public static synchronized JCoDestination getDestination() throws ConexionSAPException {

        JCoDestination jcoDestination = null;

            if (Environment.isDestinationDataProviderRegistered()) {
                try {

                    jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
                    return jcoDestination;

                } catch (JCoException ex) {

                    throw new ConexionSAPException(ex.getMessage());

                }
            }

        // Create new connection
        if(jcoProvider == null) init();

        // Get connection
        try {

            jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
            return jcoDestination;
            
        } catch (JCoException ex) {
        
            throw new ConexionSAPException(ex.getMessage());

        }

    }

    // Initialize connection to SAP
    public static synchronized void init() throws ConexionSAPException {

        SAPVO sap = new SAPVO();
        Properties properties = new Properties();

        if(jcoProvider == null) {


            // Get SAP config from database
            try {
                sap = SAPDAO.getSAPConfig();
            } catch (Exception ex) {
                throw new ConexionSAPException(ex.getMessage());
            }

             // Create connection object
            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());

        try {

            jcoProvider.changePropertiesForABAP_AS(properties);

        } catch (Exception e) {

            throw new ConexionSAPException(e.getMessage());

        }

    }

    public static synchronized void change(SAPVO sap) throws ConexionSAPException {

        Properties properties = new Properties();

        // If connection is null create a new one
        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());

        try {

            jcoProvider.changePropertiesForABAP_AS(properties);

        } catch (Exception e) {

            throw new ConexionSAPException(e.getMessage());

        }


    }

    // Prevent instantiation by clone
    @Override
    public Object clone() throws CloneNotSupportedException {
        
        throw new CloneNotSupportedException();

    }

}

JCo 提供者实现:

package es.grupotec.ejb.SAP;

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

public class JCOProvider implements DestinationDataProvider {

    private String SAP_SERVER = "JWM";
    private DestinationDataEventListener eventListener;
    private Properties ABAP_AS_properties;

    public JCOProvider(){

    }
    
    public JCOProvider(SAPVO sap){

        ABAP_AS_properties = new 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());

        try {
            if (!Environment.isDestinationDataProviderRegistered())
                Environment.registerDestinationDataProvider(this);
            else changePropertiesForABAP_AS(ABAP_AS_properties);
        } catch (Exception ex) {
            String msg = ex.getMessage();
        }

    }

    @Override
    public Properties getDestinationProperties(String name) {

        if (name.equals(SAP_SERVER) && ABAP_AS_properties!=null) return ABAP_AS_properties;
        else return null;
        
    }

    @Override
    public boolean supportsEvents() {
        return true;
    }

    @Override
    public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
        this.eventListener = eventListener;
    }

 public void changePropertiesForABAP_AS(Properties properties) throws ConexionSAPException {

        try {
            
            if (!Environment.isDestinationDataProviderRegistered()) {

                if (ABAP_AS_properties == null) ABAP_AS_properties = properties;
                Environment.registerDestinationDataProvider(this);

            }

            if (properties == null) {

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

            } else {

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

            }

        } catch (Exception ex) {

            throw new ConexionSAPException(ex.getMessage());
            
        }

 }
    
}

最佳答案

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

让 JVM 卸载 native 库是一项极其令人沮丧的工作。 JNI 规范规定,当与提供实现的类关联的类加载器被卸载时, native 库将被卸载,但在 JVM 中尝试强制类加载器卸载实际上是不可能的。

如果您的 EAR 文件包含 sapjco3.jar,每次重新加载代码时都会重新加载它。这很可能会导致异常,因为 native 库无法加载多次,并且几乎无法卸载 native 代码。因此,您可能会考虑将 sapjco3.jar 放在 J2EE 容器之外,让 J2EE 引擎在启动时加载该库一次,而不是将其放入 EAR 中并一遍又一遍地重新加载。

关于java - SAP JCo 连接器在 GlassFish v2.1 中永久加载(无法卸载),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1899888/

相关文章:

session - java中 session 超时删除cookie

java - 如何获取jar文件父依赖关系?

glassfish - JAX-RS 在 Glassfish 4 上启用 CORS(访问控制允许来源)

java - 为什么方法引用与具有不同参数数量的功能接口(interface)兼容?

java - HttpClient 4.4.1 不支持 TLS_DHE_RSA_WITH_AES_256_CBC_SHA

java - 访问我已上传到 tomcat 服务器的图像

java - Spring Boot测试RestTemplate : Pass along session id

java - 为什么我应该将 Boolean 作为参数而不是 "boolean"传递?

java - 为什么 Alfresco Explorer 3.4e CE 在 Glassfish 3.1.1 中部署时不显示登录表单?

java - 如何向 glassfish 添加 Interbase 连接池?