SpringBoot啟動時自動加載JCO連接(支持多個JCO連接)

3 篇文章 0 订阅
2 篇文章 0 订阅

背景:

有報表項目需要抓取多個SAP主機的資料(RFC),之前的的方式是配置到數據庫,使用時臨時加載切換。後來找到資料實現隨Spingboot自動加載的實現方式,此方式僅需要數據庫配置好JCO連接,項目啟動后直接按照名字取用即可。故做技術整理。

1.關鍵文件CustomDestinationDataProvider

實現DestinationDataProvider接口,獲取JCO連接配置,重寫JCO事件監聽(對Destination的監聽與通知),JCO連接配置的安全存儲。(也可以參考代碼中的英文注釋)

import java.util.HashMap;
import java.util.Properties;

import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.ext.DataProviderException;
import com.sap.conn.jco.ext.DestinationDataEventListener;
import com.sap.conn.jco.ext.DestinationDataProvider;

/**
 * Each application using Java Connector 3 deals with destinations. A destination represents a logical address
 * of an ABAP system and thus separates the destination configuration from application logic. JCo retrieves
 * the destination parameters required at runtime from DestinationDataProvider and ServerDataProvider registered
 * in the runtime environment. If no provider is registered, JCo uses the default implementation that reads the
 * configuration from a properties file. It is expected that each environment provides a suitable
 * implementation that meets security and other requirements. Furthermore, only one DestinationDataProvider
 * and only one ServerDataProvider can be registered per process. The reason behind this design decision
 * is the following: the provider implementations are part of the environment infrastructure.
 * The implementation should not be application specific, and in particular must be separated from
 * application logic.
 *
 * This example demonstrates a simple implementation of the DestinationDataProvider interface and shows how
 * to register it. A real world implementation should save the configuration data in a secure way.
 */
public class CustomDestinationDataProvider
{
    //The custom destination data provider implements DestinationDataProvider and
    //provides an implementation for at least getDestinationProperties(String).
    //Whenever possible the implementation should support events and notify the JCo runtime
    //if a destination is being created, changed, or deleted. Otherwise JCo runtime
    //will check regularly if a cached destination configuration is still valid which incurs
    //a performance penalty.
    static class MyDestinationDataProvider implements DestinationDataProvider
    {
        private DestinationDataEventListener eL;
        private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();
        
        public Properties getDestinationProperties(String destinationName)
        {
            try
            {
                //read the destination from DB
                Properties p = secureDBStorage.get(destinationName);
                if(p!=null)
                {
                    //check if all is correct, for example
                    if(p.isEmpty())
                        throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION, "destination configuration is incorrect", null);
                    return p;
                }
                
                return null;
            }
            catch(RuntimeException re)
            {
                throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR, re);
            }
        }

        //An implementation supporting events has to retain the eventListener instance provided
        //by the JCo runtime. This listener instance shall be used to notify the JCo runtime
        //about all changes in destination configurations.
        public void setDestinationDataEventListener(DestinationDataEventListener eventListener)
        {
            this.eL = eventListener;
        }

        public boolean supportsEvents()
        {
            return true;
        }

        //implementation that saves the properties in a very secure way
        void changeProperties(String destName, Properties properties)
        {
            synchronized(secureDBStorage)
            {
                if(properties==null)
                {
                    if(secureDBStorage.remove(destName)!=null)
                        eL.deleted(destName);
                }
                else
                {
                    secureDBStorage.put(destName, properties);
                    eL.updated(destName); // create or updated
                }
            }
        }
    } // end of MyDestinationDataProvider
    
//    //business logic
    JCoDestination executeCalls(String destName)
    {
        JCoDestination dest = null;
        try
        {
            dest = JCoDestinationManager.getDestination(destName);
            dest.ping();
            System.out.println("Destination " + destName + " works");
        }
        catch(JCoException e)
        {
            e.printStackTrace();
            System.out.println("Execution on destination " + destName+ " failed");
        }
        return dest;
    }
      
}

2.關鍵文件JcoRegisterAfterStartup

聲明CustomDestinationDataProvider,讀取數據庫里JCO連接配置數據,循環配置List動態放入JCO環境中,同時放入內存

import java.util.List;
import java.util.Properties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.abc.provider.entity.RelSapConfigT;
import com.abc.provider.service.JcoConnService;
import com.sap.conn.jco.ext.DestinationDataProvider;

//no use
@Component
public class JcoRegisterAfterStartup implements ApplicationListener<ContextRefreshedEvent> {

	@Autowired
	private JcoConnService jcoConnService;

	
	@Override
	public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {

		List<RelSapConfigT> sapConfigTList = jcoConnService.getAllJcoConn();
		
		if (!CollectionUtils.isEmpty(sapConfigTList)) {
			CustomDestinationDataProvider.MyDestinationDataProvider myProvider = new CustomDestinationDataProvider.MyDestinationDataProvider();
	        
	        //register the provider with the JCo environment;
	        //catch IllegalStateException if an instance is already registered
	        try
	        {
	            com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider);
	        }
	        catch(IllegalStateException providerAlreadyRegisteredException)
	        {
	            //somebody else registered its implementation, 
	            //stop the execution
	            throw new Error(providerAlreadyRegisteredException);
	        }
			for (RelSapConfigT sc : sapConfigTList) {
				Properties jcoInfo = initParam(sc);
				 myProvider.changeProperties(sc.getJcoName(), jcoInfo);
				 CustomDestinationDataProvider test = new CustomDestinationDataProvider();
				 test.executeCalls(sc.getJcoName());
			}

		}
	}

	public Properties initParam(RelSapConfigT sc) {
		// TODO Auto-generated method stub
		Properties connectProperties = new Properties();
        connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST,sc.getJcoAshost());
        connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR,sc.getJcoSysnr());
        connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT,sc.getJcoClient());
        connectProperties.setProperty(DestinationDataProvider.JCO_USER,sc.getJcoUser());
        connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD,sc.getJcoPasswd());
        connectProperties.setProperty(DestinationDataProvider.JCO_LANG,sc.getJcoLang());
        connectProperties.setProperty(DestinationDataProvider.JCO_MAX_GET_TIME,sc.getJcoMaxGetTime().toString());
        connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT,sc.getJcoPeakLimit().toString());
        connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, sc.getJcoPoolCapacity().toString());
        System.out.println("Loading jco conn info:"+sc.getJcoName()); 

        return connectProperties;
	}
}

3.JCO連接資料表結構

 4.項目啟動、調用及日誌

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值