You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在运行时更新Spring Bean以连接多台SAP服务器?

实现Spring环境下Hibersap多SAP服务器动态切换连接

问题背景

我需要通过Session Manager连接SAP服务器,当前使用Spring Bean创建Session Manager,配置信息来自hibersap.xml。此前仅连接单台服务器,现在需要连接名为BHD和AHD的两台及以上服务器,但不清楚如何在运行时动态切换配置,实现连接不同服务器的需求。

现有配置文件与代码

hibersap.xml配置

<session-manager name="BHD">
    <context>org.hibersap.execution.jco.JCoContext</context>
    <properties>
        <property name="jco.client.client" value="111" />
        <property name="jco.client.user" value="AAA" />
        <property name="jco.client.passwd" value="11Q1Q1Q1Q" />
        <property name="jco.client.ashost" value="11.11.11.11" />
        <property name="jco.client.sysnr" value="00" />
    </properties>
    <annotated-classes>
        <annotated-class>com.ldap.connection.sap.bapi.RfcLdapParameters</annotated-class>
        <annotated-class>com.ldap.connection.sap.bapi.RfcSapUserDetails</annotated-class>
        <annotated-class>com.ldap.connection.sap.bapi.UsernameAndMailModel</annotated-class>
    </annotated-classes>
</session-manager>
<session-manager name="AHD">
    <context>org.hibersap.execution.jco.JCoContext</context>
    <properties>
        <property name="jco.client.client" value="222" />
        <property name="jco.client.user" value="BBB" />
        <property name="jco.client.passwd" value="2Q2Q2Q2Q22" />
        <property name="jco.client.ashost" value="22.22.22.22" />
        <property name="jco.client.sysnr" value="00" />
    </properties>
    <annotated-classes>
        <annotated-class>com.ldap.connection.sap.bapi.RfcLdapParameters</annotated-class>
        <annotated-class>com.ldap.connection.sap.bapi.RfcSapUserDetails</annotated-class>
        <annotated-class>com.ldap.connection.sap.bapi.UsernameAndMailModel</annotated-class>
    </annotated-classes>
</session-manager>

当前Spring配置类

@Configuration
@Slf4j
public class HibersapConfiguration {    

@Bean
public SessionManager sessionManager() {
    String sname = System.getProperty("java.systemname");
    AnnotationConfiguration configuration = null;
    
    if(sname != null) {
        if(BtcConstants.LIVE_SYSTEM_NAME.equals(sname)) {
            log.info("SAP üretim canlı sisteme bağlanılıyor...");
        }
        
        if(BtcConstants.DEV_SYSTEM_NAME.equals(sname)){
            configuration = new AnnotationConfiguration("BHD");
            log.info("SAP üretim dev sisteme bağlanılıyor...");
        }
        
    }else {
        configuration = new AnnotationConfiguration("BHD");
        log.info("Local'den SAP üretim dev sisteme bağlanılıyor...");
    }
    
    
    return configuration.buildSessionManager();
 } }

仓库类代码

@Slf4j
@Repository
public class SapUserRepository implements SapUserRepositoryI {

private final SessionManager sessionManager;

public SapUserRepository(SessionManager sessionManager) {
    this.sessionManager = sessionManager;
}

@Override
public List<SapUser> findPersonalDetailFromSap(Date currentDate, String pernr) {

    List<SapUser> sapUserList = new ArrayList<SapUser>();
    RfcSapUserDetails details = new RfcSapUserDetails();
    details.setCurrentDate(currentDate);
    details.setPernr(pernr);
    
    Session session = null;
    if(sessionManager != null) {
        log.info("'findPersonalDetailFromSap' için session açıldı");
        session = sessionManager.openSession();
        
        try {
            log.info("Personel verileri çekiliyor...");
            session.execute(details);
            sapUserList = details.getSapUserList();
        } finally {
            session.close();
            log.info("session kapatıldı");
        }
    }else {
        log.error("sessionManager null geldi !");
    }

    return sapUserList;
}

解决方案

方案一:注册多个SessionManager Bean,按名称动态获取

这种方式适合服务器数量固定的场景,直接为每个SAP服务器创建独立的SessionManager Bean,使用时通过名称获取对应实例。

修改Spring配置类

@Configuration
@Slf4j
public class HibersapConfiguration {    

    @Bean(name = "bhdSessionManager")
    public SessionManager bhdSessionManager() {
        AnnotationConfiguration configuration = new AnnotationConfiguration("BHD");
        log.info("初始化BHD SAP服务器连接...");
        return configuration.buildSessionManager();
    }

    @Bean(name = "ahdSessionManager")
    public SessionManager ahdSessionManager() {
        AnnotationConfiguration configuration = new AnnotationConfiguration("AHD");
        log.info("初始化AHD SAP服务器连接...");
        return configuration.buildSessionManager();
    }
}

修改仓库类,动态获取对应SessionManager

通过注入ApplicationContext,根据业务传入的服务器名称获取对应Bean:

@Slf4j
@Repository
public class SapUserRepository implements SapUserRepositoryI {

    private final ApplicationContext applicationContext;

    public SapUserRepository(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public List<SapUser> findPersonalDetailFromSap(Date currentDate, String pernr, String serverName) {
        // 拼接Bean名称,比如传入"BHD"则获取"bhdSessionManager"
        String beanName = serverName.toLowerCase() + "SessionManager";
        SessionManager sessionManager = applicationContext.getBean(beanName, SessionManager.class);
        
        List<SapUser> sapUserList = new ArrayList<SapUser>();
        RfcSapUserDetails details = new RfcSapUserDetails();
        details.setCurrentDate(currentDate);
        details.setPernr(pernr);
        
        Session session = null;
        if(sessionManager != null) {
            log.info("'findPersonalDetailFromSap' için session açıldı");
            session = sessionManager.openSession();
            
            try {
                log.info("Personel verileri çekiliyor...");
                session.execute(details);
                sapUserList = details.getSapUserList();
            } finally {
                session.close();
                log.info("session kapatıldı");
            }
        }else {
            log.error("sessionManager null geldi !");
        }

        return sapUserList;
    }
}

方案二:实现SessionManager工厂类,按需创建缓存实例

这种方式更灵活,适合服务器数量不固定或需要动态加载配置的场景,通过工厂类统一管理SessionManager实例,避免重复创建。

创建SessionManager工厂类

@Component
public class SessionManagerFactory {

    // 缓存已创建的SessionManager,避免重复初始化
    private final Map<String, SessionManager> sessionManagerCache = new ConcurrentHashMap<>();

    public SessionManager getSessionManager(String serverName) {
        // 不存在则创建,存在则直接返回缓存实例
        return sessionManagerCache.computeIfAbsent(serverName, this::buildSessionManager);
    }

    private SessionManager buildSessionManager(String serverName) {
        AnnotationConfiguration configuration = new AnnotationConfiguration(serverName);
        log.info("初始化{} SAP服务器连接...", serverName);
        return configuration.buildSessionManager();
    }

    // 可选:添加刷新缓存的方法,用于配置更新时重新创建实例
    public void refreshSessionManager(String serverName) {
        sessionManagerCache.remove(serverName);
        getSessionManager(serverName);
    }
}

修改仓库类,注入工厂类

@Slf4j
@Repository
public class SapUserRepository implements SapUserRepositoryI {

    private final SessionManagerFactory sessionManagerFactory;

    public SapUserRepository(SessionManagerFactory sessionManagerFactory) {
        this.sessionManagerFactory = sessionManagerFactory;
    }

    @Override
    public List<SapUser> findPersonalDetailFromSap(Date currentDate, String pernr, String serverName) {
        SessionManager sessionManager = sessionManagerFactory.getSessionManager(serverName);
        
        List<SapUser> sapUserList = new ArrayList<SapUser>();
        RfcSapUserDetails details = new RfcSapUserDetails();
        details.setCurrentDate(currentDate);
        details.setPernr(pernr);
        
        Session session = null;
        if(sessionManager != null) {
            log.info("'findPersonalDetailFromSap' için session açıldı");
            session = sessionManager.openSession();
            
            try {
                log.info("Personel verileri çekiliyor...");
                session.execute(details);
                sapUserList = details.getSapUserList();
            } finally {
                session.close();
                log.info("session kapatıldı");
            }
        }else {
            log.error("sessionManager null geldi !");
        }

        return sapUserList;
    }
}

注意事项

  • SessionManager实例是线程安全的,因此可以安全缓存复用,无需每次请求都创建新实例。
  • 如果SAP服务器配置可能动态变更,可在工厂类中添加缓存刷新方法,触发重新初始化SessionManager。
  • 根据业务场景选择合适的方案:固定服务器数量用方案一,动态扩展用方案二。

内容的提问来源于stack exchange,提问作者Cemal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:27:01