我对GlassFish和SAP JCo连接器(sapjco3.jar)有问题
我在启动J2EE应用程序(jwm.ear)时加载它,并在第一次需要连接到SAP时以单例形式对其进行初始化。
问题在于此jar始终保持在内存中初始化,如果需要更改单个参数,则需要重新启动glassfish来卸载已初始化的连接。停止或取消部署该应用程序不会卸载sapjco.jar,并且进一步部署该应用程序将永远不会获得新的连接参数,第一次初始化将一直保持到GlassFish重新启动为止。
有人知道如何卸载或重新初始化该库吗?最好甚至在不重新部署应用程序的情况下,在第一次激活该应用程序时,我都有对jcoProvider的引用,下一次激活将获得对jcoProvider的空引用,但jcoProvider会继续在内存中实例化初始值。
问候!
笔记:
GlassFish是Windows 2008 Server中的2.1版,jdk是1.6.0.14
sapjco3.jar和sapjco3.dll被复制到\ domains \ domain1 \ lib \ ext,并且它们是SAP Java连接器的版本3。
Singleton获取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;
如果(Environment.isDestinationDataProviderRegistered()){
尝试{
jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
返回jcoDestination;
} catch(JCoException ex){
抛出新的ConexionSAPException(ex.getMessage());
}
}
//创建新的连接
if(jcoProvider == null)init();
//获取连接
尝试{
jcoDestination = JCoDestinationManager.getDestination(SAP_SERVER);
返回jcoDestination;
} catch(JCoException ex){
抛出新的ConexionSAPException(ex.getMessage());
}
}
//初始化与SAP的连接
公共静态同步的void init()引发ConexionSAPException {
SAPVO sap =新的SAPVO();
属性properties = new Properties();
if(jcoProvider == null){
//从数据库获取SAP配置
尝试{
sap = SAPDAO.getSAPConfig();
} catch(异常例外){
抛出新的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(properties);
} catch(Exception e){
抛出新的ConexionSAPException(e.getMessage());
}
}
公共静态同步的无效更改(SAPVO sap)引发ConexionSAPException {
属性properties = new Properties();
//如果连接为空,则创建一个新的
if(jcoProvider == null)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(properties);
} catch(Exception e){
抛出新的ConexionSAPException(e.getMessage());
}
}
//通过克隆防止实例化
@Override
公共对象clone()抛出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 eventListener;
私有属性ABAP_AS_properties;
公共JCOProvider(){
}
公开JCOProvider(SAPVO SAP){
ABAP_AS_properties =新的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());
尝试{
如果(!Environment.isDestinationDataProviderRegistered())
Environment.registerDestinationDataProvider(this);
否则changePropertiesForABAP_AS(ABAP_AS_properties);
} catch(异常例外){
字符串msg = ex.getMessage();
}
}
@Override
public Properties getDestinationProperties(String name){
如果(name.equals(SAP_SERVER)&& ABAP_AS_properties!= null)返回ABAP_AS_properties;
否则返回null;
}
@Override
public boolean supportEvents(){
返回true;
}
@Override
公共无效setDestinationDataEventListener(DestinationDataEventListener eventListener){
this.eventListener = eventListener;
}
公共无效的changePropertiesForABAP_AS(属性属性)引发ConexionSAPException {
尝试{
如果(!Environment.isDestinationDataProviderRegistered()){
如果(ABAP_AS_properties == null)ABAP_AS_properties =属性;
Environment.registerDestinationDataProvider(this);
}
如果(属性==空){
如果(eventListener!= null)eventListener.deleted(SAP_SERVER);
ABAP_AS_properties = null;
}其他{
ABAP_AS_properties =属性;
如果(eventListener!= null)eventListener.updated(SAP_SERVER);
}
} catch(异常例外){
抛出新的ConexionSAPException(ex.getMessage());
}
}
}
最佳答案
您的问题可能与以下事实有关:此处涉及一些本机代码。甚至对于JCo 3都是如此。尽管JCo 3不再使用本机RFC库,但它仍然需要JNI与CPIC层进行通信。
让JVM卸载本机库是一项极大的挫败。 JNI规范指出,与提供实现的类相关联的ClassLoader会被卸载时,将卸载本机库,但是在JVM中几乎不可能尝试强制ClassLoader卸载。
如果您的EAR文件包含sapjco3.jar,则每次重新加载代码时都会重新加载该文件。这很可能会导致异常,因为不能多次加载本机库,并且实际上没有办法卸载本机代码。因此,您可能考虑将sapjco3.jar放置在J2EE容器之外,并让您的J2EE引擎在启动时一次加载该库,而不是将其放入反复加载的EAR中。