我在使用 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/