This commit is contained in:
Rinjae
2025-09-05 17:16:26 +09:00
commit c54ef1903f
4947 changed files with 817291 additions and 0 deletions
@@ -0,0 +1,86 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.eactive.eai.rms.data.config;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class ConfigurableMultiTenantConnectionProvider implements MultiTenantConnectionProvider {
private static final long serialVersionUID = 1L;
@Autowired
private transient DataSource dataSource;
@Override
public Connection getAnyConnection() throws SQLException {
return dataSource.getConnection();
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connection.close();
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
return changeSchema(dataSource.getConnection(), tenantIdentifier);
}
public Connection changeSchema(Connection connection, String tenantIdentifier) throws SQLException {
// connection.setSchema() 를 이용하여 schema를 설정 하려 했으나 postgresql 에서는 대문자로 넣으면 에러가
// 발생 한다. 에러가 발생 하지 않게 하려면 applicationContext-datasource.xml 에서 스키마명을 소문자로 변경
// 한다.
// 일단 schema 설정을 하지 않고 사용
String schema = DataSourceTypeManager.getDataSourceType(tenantIdentifier).getSchema();
// connection.setSchema(schema);
log.debug("change schema : {} connection : {}", schema, connection);
return connection;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
connection.close();
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(@SuppressWarnings("rawtypes") Class aClass) {
return false;
}
@Override
public <T> T unwrap(Class<T> aClass) {
throw new UnsupportedOperationException("Can't unwrap this.");
}
}
@@ -0,0 +1,53 @@
package com.eactive.eai.rms.data.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.eactive.eai.data.jpa.BaseRepositoryImpl;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
import com.eactive.eai.rms.data.EMSDataSource;
@Configuration
@EnableTransactionManagement
@EnableJpaAuditing(auditorAwareRef = "EMSAuditorAware")
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryForEMS", transactionManagerRef = "transactionManagerForEMS", basePackages = {"com.eactive.eai", "com.eactive.apim.portal"}, repositoryBaseClass = BaseRepositoryImpl.class, includeFilters = @Filter(classes = EMSDataSource.class))
public class EMSTenantConfiguration {
@Bean("entityManagerFactoryForEMS")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryForEMS(
@Qualifier(DataSourceTypeManager.MONITORING) DataSource dataSource,
@Qualifier("hibernateProperties") Properties hibernateProperties) {
LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
bean.setDataSource(dataSource);
bean.setPackagesToScan("com.eactive.eai.data", "com.eactive.eai.rms.data", "com.eactive.apim.portal");
bean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
bean.setJpaProperties(hibernateProperties);
return bean;
}
@Bean("transactionManagerForEMS")
public TransactionManager transactionManager(@Qualifier(DataSourceTypeManager.MONITORING) DataSource dataSource,
@Qualifier("entityManagerFactoryForEMS") EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(dataSource);
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
}
@@ -0,0 +1,56 @@
package com.eactive.eai.rms.data.config;
import java.lang.annotation.Annotation;
import java.util.function.Consumer;
import javax.persistence.EntityManagerFactory;
import javax.persistence.metamodel.EntityType;
import org.hibernate.annotations.Table;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class EntityTablePrinter implements ApplicationListener<ContextRefreshedEvent> {
private EntityManagerFactory entityManagerFactory;
@Autowired
public EntityTablePrinter(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (log.isDebugEnabled() && event.getApplicationContext().getParent() == null) {
log.debug("################### TABLE INFO ###################");
entityManagerFactory.getMetamodel().getEntities().parallelStream().forEach(this::printEntityTableInfo);
}
}
private void printEntityTableInfo(EntityType<?> entityType) {
String entityName = entityType.getName();
// Hibernate Table 정보 출력
printTableInfo(entityType, Table.class,
table -> log.debug("Table Name : {} = {} ({})", table.appliesTo(), entityName, table.comment()));
// JPA Table 정보 출력
printTableInfo(entityType, javax.persistence.Table.class,
table -> log.debug("Table Name : {} = {}", table.name(), entityName));
}
private <T extends Annotation> void printTableInfo(EntityType<?> entityType, Class<T> annotationClass,
Consumer<T> printer) {
T tableAnnotation = entityType.getBindableJavaType().getAnnotation(annotationClass);
if (tableAnnotation != null) {
printer.accept(tableAnnotation);
}
}
}
@@ -0,0 +1,18 @@
package com.eactive.eai.rms.data.config;
import javax.persistence.EntityManagerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.support.SharedEntityManagerBean;
@Configuration
public class JPAConfiguration {
@Bean("entityManager")
public SharedEntityManagerBean entityManager(EntityManagerFactory entityManagerFactory) {
SharedEntityManagerBean sharedEntityManagerBean = new SharedEntityManagerBean();
sharedEntityManagerBean.setEntityManagerFactory(entityManagerFactory);
return sharedEntityManagerBean;
}
}
@@ -0,0 +1,86 @@
package com.eactive.eai.rms.data.config;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.hibernate.cfg.AvailableSettings;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.eactive.eai.data.jpa.BaseRepositoryImpl;
import com.eactive.eai.rms.data.EMSDataSource;
import com.eactive.kakao.rolling.TableSuffixResolver;
@Configuration
@EnableScheduling
@EnableTransactionManagement
@EnableJpaAuditing(auditorAwareRef = "EMSAuditorAware")
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager", basePackages = {
"com.eactive.eai", }, repositoryBaseClass = BaseRepositoryImpl.class, excludeFilters = {
@Filter(classes = EMSDataSource.class)
,
// @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { DataLoaderRepository.class })
})
public class MultitenantConfiguration {
@Bean("entityManagerFactory")
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
@Qualifier("hibernateProperties") Properties hibernateProperties) {
LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
bean.setDataSource(dataSource);
bean.setPackagesToScan("com.eactive.eai.data", "com.eactive.eai.rms.data");
bean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
bean.setJpaProperties(hibernateProperties);
Map<String, Object> settings = new HashMap<>();
settings.put(AvailableSettings.MULTI_TENANT, "SCHEMA");
settings.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, configurableMultiTenantConnectionProvider());
settings.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantIdentifierResolver());
bean.setJpaPropertyMap(settings);
return bean;
}
@Bean("transactionManager")
@Primary
public TransactionManager transactionManager(DataSource dataSource, EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(dataSource);
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
@Bean
public ConfigurableMultiTenantConnectionProvider configurableMultiTenantConnectionProvider() {
return new ConfigurableMultiTenantConnectionProvider();
}
@Bean
public TenantIdentifierResolver tenantIdentifierResolver() {
return new TenantIdentifierResolver();
}
@Bean
public TableSuffixResolver tableSuffixResolver() {
return () -> "";
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.eactive.eai.rms.data.config;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
import com.eactive.eai.rms.common.datasource.DataSourceType;
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
@Component
public class TenantIdentifierResolver implements CurrentTenantIdentifierResolver {
private static final Logger logger = LoggerFactory.getLogger(TenantIdentifierResolver.class);
@Override
public String resolveCurrentTenantIdentifier() {
DataSourceType dataSourceType = DataSourceContextHolder.getDataSourceType();
if (dataSourceType == null) {
dataSourceType = DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING);
logger.debug("DataSource가 명시적으로 선택되지 않았으므로, MONITORING DataSource를 사용합니다.");
}
return dataSourceType != null ? dataSourceType.getName() : null;
}
@Override
public boolean validateExistingCurrentSessions() {
return true;
}
}