DestinationDataProvider

DestinationDataProvider

我对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中。

10-05 22:37