You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 lines
11 KiB

package com.bsmlab.dfx.agent.config;
import com.bsmlab.dfx.agent.DfxAgentApplication;
import com.bsmlab.dfx.agent.config.datasource.DynamicDataSourceService;
import com.bsmlab.dfx.agent.config.datasource.DynamicRoutingDataSource;
import com.bsmlab.dfx.agent.config.datasource.RefreshableSqlSessionFactoryBean;
import io.micrometer.common.util.StringUtils;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.annotation.MapperScans;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.concurrent.Executor;
@Slf4j
@Getter
@Configuration
@RequiredArgsConstructor
@MapperScans({
@MapperScan("com.bsmlab.dfx.agent")
})
public class DfxAgentConfiguration {
// gradle bootRun 실행 설정
// bootRun D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json"
// command line java 실행 설정
// java -jar dfxagent.jar --setting.file=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json
//example: setting.file=D:\projects\bsm-lab\dfx\dfxagent\src\docs\settings-examples\dfxagent.json
@Value("${setting.file}")
private String settingFile;
private String pid;
private Map<String, SqlSessionFactory> temporarySqlSessionFactoryMap = new HashMap<>();
Map<String, DataSourceTransactionManager> temporaryTransactionManagerMap = new HashMap<>();
// agent 설정 관리자. 대부분의 기능에 필요함
@Bean(name = "agentConfigReader")
public AgentConfigReader agentConfigReader() throws URISyntaxException, IOException { // 실행확인됨
if(StringUtils.isBlank(this.settingFile)) {
log.error("cannot found a setting file. {}", this.settingFile);
log.error("exit application");
System.exit(0);
}
AgentConfigReader agentConfigReader = new AgentConfigReader();
agentConfigReader.loadConfigFile(this.settingFile);
// Process ID를 찾아 app_home/proc/pid 파일에 기록한다. 이후 shutdown.sh에서 해당 pid를 사용하여 kill -9 pid 를 실행한다.
this.pid = String.valueOf(ProcessHandle.current().pid());
URL location = DfxAgentApplication.class.getProtectionDomain().getCodeSource().getLocation();
URI uri = location.toURI();
File file;
if ("file".equalsIgnoreCase(uri.getScheme())) {
// 파일 시스템 상의 경로
file = new File(uri);
}
else if ("jar".equalsIgnoreCase(uri.getScheme()) || location.toString().startsWith("jar:")) {
// JAR 내부 경로일 경우
String path = location.toString();
log.debug("path: {}", path);
if (path.startsWith("jar:")) {
path = path.substring(4, path.indexOf("!") - 1);
path = path.substring(path.indexOf(":") + 1, path.lastIndexOf("/"));
}
log.debug("path: {}", path);
file = new File(path);
}
else {
// 파일 시스템 상의 경로
file = new File(uri);
}
String procDirectoryPath = file.getParent() + File.separator + "proc";
File procFile = new File(procDirectoryPath);
if(!procFile.exists()) {
procFile.mkdirs();
}
Path pidFilePath = Path.of(procDirectoryPath + File.separator, "dfxagent.pid");
Files.writeString(pidFilePath, pid, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
return agentConfigReader;
}
// 다중 데이터 소스 생성
@Bean(name = "dynamicRoutingDataSource")
public DynamicRoutingDataSource dynamicRoutingDataSource(AgentConfigReader agentConfigReader) throws IOException { // 실행확인됨
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<String, SqlSessionFactory> sqlSessionFactoryMap = new HashMap<>();
Map<String, DataSourceTransactionManager> transactionManagerMap = new HashMap<>();
List<String> xmlPathList = agentConfigReader.getAgentConfigDto().getSqlMapperLocations();
List<Resource> resourceList = new ArrayList<>();
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
for(String pathString : xmlPathList) {
Resource[] resourceArray = pathMatchingResourcePatternResolver.getResources("file:" + pathString);
resourceList.addAll(Arrays.asList(resourceArray));
}
List<AgentConfigDto.DataSourceConfig> dataSourceConfigList = agentConfigReader.getAgentConfigDto().getDataSourceConfig();
for(AgentConfigDto.DataSourceConfig dataSourceConfig : dataSourceConfigList) {
try {
BasicDataSource dataSource = createBasicDataSource(dataSourceConfig);
SqlSessionFactoryBean sqlSessionFactoryBean = new RefreshableSqlSessionFactoryBean();//new SqlSessionFactoryBean();
org.apache.ibatis.session.Configuration mybatisConfiguration = new org.apache.ibatis.session.Configuration();
sqlSessionFactoryBean.setConfiguration(mybatisConfiguration);
sqlSessionFactoryBean.setFailFast(true);
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(resourceList.toArray(new Resource[0]));
sqlSessionFactoryBean.afterPropertiesSet();
sqlSessionFactoryMap.put(dataSourceConfig.getDataSourceId(), sqlSessionFactoryBean.getObject());
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
transactionManagerMap.put(dataSourceConfig.getDataSourceId(), transactionManager);
dynamicRoutingDataSource.addDataSource(dataSourceConfig.getDataSourceId(), dataSource);
} catch (Exception e) {
log.error("DynamicRoutingDataSource 생성 중 오류: {}", e.getMessage(), e);
throw new RuntimeException(e);
}
}
this.temporarySqlSessionFactoryMap = sqlSessionFactoryMap;
this.temporaryTransactionManagerMap = transactionManagerMap;
return dynamicRoutingDataSource;
}
private static BasicDataSource createBasicDataSource(AgentConfigDto.DataSourceConfig dataSourceConfig) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(dataSourceConfig.getDriverClassName());
dataSource.setUrl(dataSourceConfig.getUrl());
dataSource.setUsername(dataSourceConfig.getUsername());
dataSource.setPassword(dataSourceConfig.getPassword());
if(oracle.jdbc.driver.OracleDriver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) {
dataSource.setValidationQuery("SELECT 1 FROM DUAL");
}
else if(org.postgresql.Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) {
dataSource.setValidationQuery("SELECT 1");
}
else if(com.mysql.jdbc.Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) {
dataSource.setValidationQuery("SELECT 1");
}
else if(org.mariadb.jdbc.Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) {
dataSource.setValidationQuery("SELECT 1");
}
else if(com.ibm.db2.jcc.DB2Driver.class.getCanonicalName().equals(dataSourceConfig.getDriverClassName())) {
dataSource.setValidationQuery("SELECT 1 FROM SYSIBM.SYSDUMMY1");
}
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
dataSource.setTestOnCreate(true);
dataSource.setTestWhileIdle(true);
dataSource.setInitialSize(3);
dataSource.setMinIdle(3);
dataSource.setMaxIdle(30);
dataSource.setMaxTotal(30);
return dataSource;
}
// 다중 데이터 소스와 그에 해당하는 sqlSession, transactionManager 설정
@Bean(name = "dynamicDataSourceService")
public DynamicDataSourceService dynamicDataSourceService() { // 실행확인됨
DynamicDataSourceService dynamicDataSourceService = new DynamicDataSourceService();
dynamicDataSourceService.setSqlSessionFactoryMap(this.temporarySqlSessionFactoryMap);
dynamicDataSourceService.setTransactionManagerMap(this.temporaryTransactionManagerMap);
return dynamicDataSourceService;
}
// (수신 처리) 메시지 수신 - 저장 후 수신 메시지 처리 쓰레드 설정
@Bean(name = "dropBoxProcessorThreadPoolTaskExecutor")
public Executor dropBoxProcessorThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor dropBoxProcessorThreadPoolTaskExecutor = new ThreadPoolTaskExecutor();
dropBoxProcessorThreadPoolTaskExecutor.setCorePoolSize(30); // 최소 쓰레드
dropBoxProcessorThreadPoolTaskExecutor.setMaxPoolSize(300); // 최대 쓰레드
dropBoxProcessorThreadPoolTaskExecutor.setQueueCapacity(300); // 대기 큐
dropBoxProcessorThreadPoolTaskExecutor.setThreadNamePrefix("dropBoxProcessor-");
dropBoxProcessorThreadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true); // 종료 시 대기 여부
dropBoxProcessorThreadPoolTaskExecutor.initialize();
return dropBoxProcessorThreadPoolTaskExecutor;
}
// (송신 처리) 메시지 송신 쓰레드 설정
@Bean(name = "scheduledPostmanThreadPoolTaskScheduler")
public ThreadPoolTaskScheduler scheduledPostmanThreadPoolTaskScheduler() { // 실행확인됨
ThreadPoolTaskScheduler scheduledPostmanThreadPoolTaskScheduler = new ThreadPoolTaskScheduler();
scheduledPostmanThreadPoolTaskScheduler.setPoolSize(10);
scheduledPostmanThreadPoolTaskScheduler.setThreadNamePrefix("postman-scheduler-");
scheduledPostmanThreadPoolTaskScheduler.initialize();
return scheduledPostmanThreadPoolTaskScheduler;
}
}