fix: 去掉无用代码
This commit is contained in:
@@ -32,17 +32,8 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-mysql</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>sdk</artifactId>
|
||||
<groupId>io.dataease</groupId>
|
||||
<version>${dataease.version}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>distributed</artifactId>
|
||||
|
||||
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>io.dataease</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-mysql</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>**/*.*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -1,12 +0,0 @@
|
||||
package io.dataease;
|
||||
|
||||
import io.dataease.rpc.DeFeignRegister;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration
|
||||
@EnableFeignClients
|
||||
@Import(DeFeignRegister.class)
|
||||
public class DeFeignConfiguration {
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package io.dataease.dds;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
public class DynamicContextHolder {
|
||||
|
||||
private static final ThreadLocal<Deque<String>> CONTEXT_HOLDER = new ThreadLocal() {
|
||||
@Override
|
||||
protected Object initialValue() {
|
||||
return new ArrayDeque();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public static String peek() {
|
||||
return CONTEXT_HOLDER.get().peek();
|
||||
}
|
||||
|
||||
|
||||
public static void push(String dataSource) {
|
||||
CONTEXT_HOLDER.get().push(dataSource);
|
||||
}
|
||||
|
||||
|
||||
public static void poll() {
|
||||
Deque<String> deque = CONTEXT_HOLDER.get();
|
||||
deque.poll();
|
||||
if (deque.isEmpty()) {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package io.dataease.dds;
|
||||
|
||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
||||
|
||||
|
||||
public class DynamicDataSource extends AbstractRoutingDataSource {
|
||||
|
||||
@Override
|
||||
protected Object determineCurrentLookupKey() {
|
||||
return DynamicContextHolder.peek();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package io.dataease.dds.config;
|
||||
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ConfigurationProperties(prefix = "dynamic")
|
||||
public class DynamicDataSourceProperties {
|
||||
|
||||
private Map<String, DataSourceProperties> datasource = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, DataSourceProperties> getDatasource() {
|
||||
return datasource;
|
||||
}
|
||||
|
||||
public void setDatasource(Map<String, DataSourceProperties> datasource) {
|
||||
this.datasource = datasource;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package io.dataease.dds.config;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import io.dataease.dds.DynamicDataSource;
|
||||
import io.dataease.dds.constant.DataSourceConstant;
|
||||
import io.dataease.dds.interceptor.DSInterceptor;
|
||||
import io.dataease.dds.provider.TenantDatasourceProvider;
|
||||
import io.dataease.flyway.TenantFlywayUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
|
||||
public class DynamicDsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Value("${de.tenant.ds.lazy:false}")
|
||||
private Boolean tenantDsLazyLoad;
|
||||
|
||||
@Value("${spring.application.name}")
|
||||
private String appName;
|
||||
|
||||
@Autowired
|
||||
private DynamicDataSourceProperties properties;
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "spring.datasource")
|
||||
public DataSourceProperties dataSourceProperties() {
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public DynamicDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) {
|
||||
DynamicDataSource dynamicDataSource = new DynamicDataSource();
|
||||
//设置多个数据源的map
|
||||
Map<Object, Object> dynamicDataSourceMap = getDynamicDataSource();
|
||||
HikariDataSource defaultDataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
|
||||
dynamicDataSourceMap.put(DataSourceConstant.DATA_SOURCE_MANAGE, defaultDataSource);
|
||||
if (!tenantDsLazyLoad) {
|
||||
Map<String, DataSource> dbInfo = TenantDatasourceProvider.getDbInfo(defaultDataSource);
|
||||
if (!CollectionUtils.isEmpty(dbInfo)) {
|
||||
dynamicDataSourceMap.putAll(dbInfo);
|
||||
}
|
||||
}
|
||||
dynamicDataSource.setTargetDataSources(dynamicDataSourceMap);
|
||||
for (Map.Entry<Object, Object> entry : dynamicDataSourceMap.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
boolean isManage = key.equals(DataSourceConstant.DATA_SOURCE_MANAGE);
|
||||
try {
|
||||
TenantFlywayUtil.executeFlyway((HikariDataSource) entry.getValue(), isManage, appName);
|
||||
} catch (Exception e) {
|
||||
// 记录日志 循环继续
|
||||
}
|
||||
}
|
||||
//默认数据源
|
||||
dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
|
||||
return dynamicDataSource;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 从配置文件加载额外的数据源
|
||||
* DE官方库业务库可以从这里加载进去(客户业务库是从数据库读进去)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Map<Object, Object> getDynamicDataSource() {
|
||||
Map<String, DataSourceProperties> dataSourcePropertiesMap = properties.getDatasource();
|
||||
Map<Object, Object> targetDataSources = new HashMap<>(dataSourcePropertiesMap.size());
|
||||
dataSourcePropertiesMap.forEach((k, v) -> {
|
||||
HikariDataSource hikariDataSource = v.initializeDataSourceBuilder().type(HikariDataSource.class).build();
|
||||
targetDataSources.put(k, hikariDataSource);
|
||||
});
|
||||
return targetDataSources;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new DSInterceptor());
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package io.dataease.dds.constant;
|
||||
|
||||
public class DataSourceConstant {
|
||||
|
||||
/**
|
||||
* 这里的命名统一在配置文件命名的基础上加dataSource前缀且改小驼峰
|
||||
* 默认数据源名称
|
||||
*/
|
||||
public static final String DATA_SOURCE_MANAGE = "manege-ds";
|
||||
|
||||
/**
|
||||
* 递增可配数据源名称
|
||||
* 这里的命名统一在配置文件命名的基础上加dataSource前缀且改小驼峰
|
||||
* 后面可接着 db2... dbn 也可以根据
|
||||
*/
|
||||
public static final String DATA_SOURCE_OFFICIAL = "official-ds";
|
||||
|
||||
|
||||
public static final String DS_NAME_PREFIX = "tenant_%s_%s";
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package io.dataease.dds.interceptor;
|
||||
|
||||
import io.dataease.dds.DynamicContextHolder;
|
||||
import io.dataease.dds.constant.DataSourceConstant;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
/**
|
||||
* 不同租户不同二级域名
|
||||
* nginx下把租户ID以及租户创建时间设置在请求头
|
||||
* 获取请求头部租户ID和创建时间
|
||||
* 根据租户ID和创建时间获取租户数据源名称
|
||||
* 切换数据源
|
||||
*/
|
||||
public class DSInterceptor implements HandlerInterceptor {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
String tenant = request.getHeader("tenant");
|
||||
String time = request.getHeader("time");
|
||||
DynamicContextHolder.push(getTenantDsKey(tenant, time));
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getTenantDsKey(String tenant, String time) {
|
||||
if (null == tenant || null == time) return "official-ds";
|
||||
return String.format(DataSourceConstant.DS_NAME_PREFIX, tenant, time);
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package io.dataease.dds.provider;
|
||||
import io.dataease.utils.LogUtil;
|
||||
|
||||
|
||||
import com.zaxxer.hikari.HikariConfig;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TenantDatasourceProvider {
|
||||
|
||||
private static final String MYSQL_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";
|
||||
|
||||
private static final String DS_NAME_PREFIX = "tenant_%s_%s";
|
||||
|
||||
private static final String ALL_TENANT_SQL = "select d.*, i.create_time from tenant_db d left join tenant_info i on d.tenant_id = i.id";
|
||||
private static final String ONE_TENANT_SQL = "select d.*, i.create_time from tenant_db d left join tenant_info i on d.tenant_id = i.id where d.tenant_id = ? ";
|
||||
|
||||
|
||||
/**
|
||||
* 这里需要加上异常处理
|
||||
* 某个数据源不能构建成功 continue 不能影响全局
|
||||
* @param manage
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, DataSource> getDbInfo(DataSource manage) {
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
connection = manage.getConnection();
|
||||
statement = connection.prepareStatement(ALL_TENANT_SQL);
|
||||
resultSet = statement.executeQuery();
|
||||
List<Map<String, Object>> mapList = parseResultSet(resultSet);
|
||||
if (!CollectionUtils.isEmpty(mapList)) {
|
||||
return mapList.stream().collect(Collectors.toMap(TenantDatasourceProvider::getDsKey, TenantDatasourceProvider::buildHikari));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
} finally {
|
||||
close(connection,statement, resultSet);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Map<String, DataSource> getDbInfo(DataSource manage, Long tenantId) throws Exception{
|
||||
|
||||
|
||||
Connection connection = null;
|
||||
PreparedStatement statement = null;
|
||||
ResultSet resultSet = null;
|
||||
try {
|
||||
connection = manage.getConnection();
|
||||
statement = connection.prepareStatement(ONE_TENANT_SQL);
|
||||
statement.setLong(1, tenantId);
|
||||
resultSet = statement.executeQuery();
|
||||
List<Map<String, Object>> mapList = parseResultSet(resultSet);
|
||||
if (!CollectionUtils.isEmpty(mapList)) {
|
||||
return mapList.stream().collect(Collectors.toMap(TenantDatasourceProvider::getDsKey, TenantDatasourceProvider::buildHikari));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
} finally {
|
||||
close(connection,statement, resultSet);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private static String getDsKey(Map<String, Object> row) {
|
||||
Long tenantId = (Long) row.get("tenant_id");
|
||||
Long createTime = (Long) row.get("create_time");
|
||||
Object dsKeyObj = null;
|
||||
if (!ObjectUtils.isEmpty((dsKeyObj = row.get("ds_key")))) {
|
||||
return dsKeyObj.toString();
|
||||
}
|
||||
return String.format(DS_NAME_PREFIX, tenantId.toString(), createTime.toString());
|
||||
}
|
||||
|
||||
private static DataSource buildHikari(Map<String, Object> param) {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setDriverClassName(param.getOrDefault("driver_class", MYSQL_DRIVER_CLASS_NAME).toString());
|
||||
config.setJdbcUrl(param.get("url").toString());
|
||||
config.setUsername(param.get("username").toString());
|
||||
config.setPassword(param.get("pwd").toString());
|
||||
HikariDataSource hikariDataSource = new HikariDataSource(config);
|
||||
return hikariDataSource;
|
||||
}
|
||||
|
||||
private static List<Map<String, Object>> parseResultSet(ResultSet resultSet) throws Exception{
|
||||
List<Map<String, Object>> resultList = new ArrayList<>();
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
int columnCount = metaData.getColumnCount();
|
||||
while (resultSet.next()) {
|
||||
Map<String, Object> row = new HashMap<>();
|
||||
for (int i = 1; i <= columnCount; i++) {
|
||||
Object cellVal = resultSet.getObject(i);
|
||||
String columnLabel = metaData.getColumnLabel(i);
|
||||
row.put(columnLabel, cellVal);
|
||||
}
|
||||
resultList.add(row);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public static void close(Connection connection, PreparedStatement statement, ResultSet rs) {
|
||||
try {
|
||||
if (connection != null && !connection.isClosed()) {
|
||||
connection.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
try {
|
||||
if (statement != null) {
|
||||
statement.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
try {
|
||||
if (rs != null && !rs.isClosed()) {
|
||||
rs.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package io.dataease.flyway;
|
||||
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.flywaydb.core.api.configuration.ClassicConfiguration;
|
||||
import org.flywaydb.core.api.configuration.Configuration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class TenantFlywayUtil {
|
||||
|
||||
private static final String FLYWAY_MANAGE_TABLE_NAME = "de_manage_version";
|
||||
|
||||
private static final String FLYWAY_TABLENAME_FORMAT = "de_tenant_%s_version";
|
||||
private static final String FLYWAY_LOCATION = "classpath:db/migration";
|
||||
private static final String FLYWAY_MANAGE_LOCATION = "classpath:db/distributed/manage";
|
||||
|
||||
|
||||
private static Configuration buildConfiguration(DataSource dataSource, boolean isManager, String appName) {
|
||||
ClassicConfiguration configuration = new ClassicConfiguration();
|
||||
configuration.setValidateOnMigrate(true);
|
||||
configuration.setBaselineOnMigrate(true);
|
||||
configuration.setTable(isManager ? FLYWAY_MANAGE_TABLE_NAME : getVersionTableName(appName));
|
||||
configuration.setEncoding(Charset.forName("utf-8"));
|
||||
configuration.setOutOfOrder(true);
|
||||
configuration.setBaselineVersionAsString("1");
|
||||
configuration.setLocationsAsStrings(isManager ? FLYWAY_MANAGE_LOCATION : FLYWAY_LOCATION);
|
||||
configuration.setDataSource(dataSource);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public static void executeFlyway(DataSource dataSource, boolean isManage, String appName) throws Exception {
|
||||
Configuration configuration = buildConfiguration(dataSource, isManage, appName);
|
||||
Flyway flyway = new Flyway(configuration);
|
||||
flyway.migrate();
|
||||
}
|
||||
|
||||
private static String getVersionTableName(String appName) {
|
||||
return String.format(FLYWAY_TABLENAME_FORMAT, appName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,408 +0,0 @@
|
||||
package io.dataease.rpc;
|
||||
|
||||
import feign.Request;
|
||||
|
||||
import io.dataease.feign.DeFeign;
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
|
||||
import org.springframework.beans.factory.config.*;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.cloud.openfeign.*;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class DeFeignRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
public DeFeignRegister() {
|
||||
}
|
||||
|
||||
static void validateFallback(final Class clazz) {
|
||||
Assert.isTrue(!clazz.isInterface(), "Fallback class must implement the interface annotated by @DeFeign");
|
||||
}
|
||||
|
||||
static void validateFallbackFactory(final Class clazz) {
|
||||
Assert.isTrue(!clazz.isInterface(), "Fallback factory must produce instances "
|
||||
+ "of fallback classes that implement the interface annotated by @DeFeign");
|
||||
}
|
||||
|
||||
static String getName(String name) {
|
||||
if (!StringUtils.hasText(name)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String host = null;
|
||||
try {
|
||||
String url;
|
||||
if (!name.startsWith("http://") && !name.startsWith("https://")) {
|
||||
url = "http://" + name;
|
||||
} else {
|
||||
url = name;
|
||||
}
|
||||
host = new URI(url).getHost();
|
||||
|
||||
} catch (URISyntaxException ignored) {
|
||||
}
|
||||
Assert.state(host != null, "Service id not legal hostname (" + name + ")");
|
||||
return name;
|
||||
}
|
||||
|
||||
static String getUrl(String url) {
|
||||
if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) {
|
||||
if (!url.contains("://")) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
try {
|
||||
new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException(url + " is malformed", e);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
static String getPath(String path) {
|
||||
if (StringUtils.hasText(path)) {
|
||||
path = path.trim();
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
if (path.endsWith("/")) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
|
||||
registerDeFeigns(metadata, registry);
|
||||
}
|
||||
|
||||
|
||||
public void registerDeFeigns(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
|
||||
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
|
||||
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
|
||||
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
|
||||
if (clients == null || clients.length == 0) {
|
||||
ClassPathScanningCandidateComponentProvider scanner = getScanner();
|
||||
scanner.setResourceLoader(this.resourceLoader);
|
||||
scanner.addIncludeFilter(new AnnotationTypeFilter(DeFeign.class));
|
||||
Set<String> basePackages = getBasePackages(metadata);
|
||||
for (String basePackage : basePackages) {
|
||||
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
|
||||
}
|
||||
} else {
|
||||
for (Class<?> clazz : clients) {
|
||||
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
|
||||
}
|
||||
}
|
||||
|
||||
for (BeanDefinition candidateComponent : candidateComponents) {
|
||||
if (candidateComponent instanceof AnnotatedBeanDefinition beanDefinition) {
|
||||
// verify annotated class is an interface
|
||||
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
|
||||
Assert.isTrue(annotationMetadata.isInterface(), "@DeFeign can only be specified on an interface");
|
||||
|
||||
Map<String, Object> attributes = annotationMetadata
|
||||
.getAnnotationAttributes(DeFeign.class.getCanonicalName());
|
||||
|
||||
registerDeFeign(registry, annotationMetadata, attributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDeFeign(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
|
||||
Map<String, Object> attributes) {
|
||||
String className = annotationMetadata.getClassName();
|
||||
if (String.valueOf(false).equals(
|
||||
environment.getProperty("spring.cloud.openfeign.lazy-attributes-resolution", String.valueOf(false)))) {
|
||||
eagerlyRegisterDeFeignBeanDefinition(className, attributes, registry);
|
||||
} else {
|
||||
lazilyRegisterDeFeignBeanDefinition(className, attributes, registry);
|
||||
}
|
||||
}
|
||||
|
||||
private void eagerlyRegisterDeFeignBeanDefinition(String className, Map<String, Object> attributes,
|
||||
BeanDefinitionRegistry registry) {
|
||||
validate(attributes);
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
|
||||
definition.addPropertyValue("url", getUrl(null, attributes));
|
||||
definition.addPropertyValue("path", getPath(null, attributes));
|
||||
String name = getName(attributes);
|
||||
definition.addPropertyValue("name", name);
|
||||
String contextId = getContextId(null, attributes);
|
||||
definition.addPropertyValue("contextId", contextId);
|
||||
definition.addPropertyValue("type", className);
|
||||
definition.addPropertyValue("dismiss404", Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
|
||||
Object fallback = attributes.get("fallback");
|
||||
if (fallback != null) {
|
||||
definition.addPropertyValue("fallback",
|
||||
(fallback instanceof Class ? fallback : ClassUtils.resolveClassName(fallback.toString(), null)));
|
||||
}
|
||||
Object fallbackFactory = attributes.get("fallbackFactory");
|
||||
if (fallbackFactory != null) {
|
||||
definition.addPropertyValue("fallbackFactory", fallbackFactory instanceof Class ? fallbackFactory
|
||||
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
|
||||
}
|
||||
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.addPropertyValue("refreshableClient", isClientRefreshEnabled());
|
||||
String[] qualifiers = getQualifiers(attributes);
|
||||
if (ObjectUtils.isEmpty(qualifiers)) {
|
||||
qualifiers = new String[]{contextId + "DeFeign"};
|
||||
}
|
||||
// This is done so that there's a way to retrieve qualifiers while generating AOT
|
||||
// code
|
||||
definition.addPropertyValue("qualifiers", qualifiers);
|
||||
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
|
||||
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
|
||||
// has a default, won't be null
|
||||
boolean primary = (Boolean) attributes.get("primary");
|
||||
beanDefinition.setPrimary(primary);
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
|
||||
registerRefreshableBeanDefinition(registry, contextId, Request.Options.class, OptionsFactoryBean.class);
|
||||
registerRefreshableBeanDefinition(registry, contextId, RefreshableUrl.class, RefreshableUrlFactoryBean.class);
|
||||
}
|
||||
|
||||
private void lazilyRegisterDeFeignBeanDefinition(String className, Map<String, Object> attributes,
|
||||
BeanDefinitionRegistry registry) {
|
||||
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
|
||||
? (ConfigurableBeanFactory) registry : null;
|
||||
Class clazz = ClassUtils.resolveClassName(className, null);
|
||||
String contextId = getContextId(beanFactory, attributes);
|
||||
String name = getName(attributes);
|
||||
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
|
||||
factoryBean.setBeanFactory(beanFactory);
|
||||
factoryBean.setName(name);
|
||||
factoryBean.setContextId(contextId);
|
||||
factoryBean.setType(clazz);
|
||||
factoryBean.setRefreshableClient(isClientRefreshEnabled());
|
||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
|
||||
factoryBean.setUrl(getUrl(beanFactory, attributes));
|
||||
factoryBean.setPath(getPath(beanFactory, attributes));
|
||||
factoryBean.setDismiss404(Boolean.parseBoolean(String.valueOf(attributes.get("dismiss404"))));
|
||||
Object fallback = attributes.get("fallback");
|
||||
if (fallback != null) {
|
||||
factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback
|
||||
: ClassUtils.resolveClassName(fallback.toString(), null));
|
||||
}
|
||||
Object fallbackFactory = attributes.get("fallbackFactory");
|
||||
if (fallbackFactory != null) {
|
||||
factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
|
||||
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
|
||||
}
|
||||
return factoryBean.getObject();
|
||||
});
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.setLazyInit(true);
|
||||
validate(attributes);
|
||||
|
||||
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
|
||||
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
|
||||
beanDefinition.setAttribute("DeFeignsRegistrarFactoryBean", factoryBean);
|
||||
|
||||
// has a default, won't be null
|
||||
boolean primary = (Boolean) attributes.get("primary");
|
||||
|
||||
beanDefinition.setPrimary(primary);
|
||||
|
||||
String[] qualifiers = getQualifiers(attributes);
|
||||
if (ObjectUtils.isEmpty(qualifiers)) {
|
||||
qualifiers = new String[]{contextId + "DeFeign"};
|
||||
}
|
||||
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
|
||||
|
||||
registerRefreshableBeanDefinition(registry, contextId, Request.Options.class, OptionsFactoryBean.class);
|
||||
registerRefreshableBeanDefinition(registry, contextId, RefreshableUrl.class, RefreshableUrlFactoryBean.class);
|
||||
}
|
||||
|
||||
private void validate(Map<String, Object> attributes) {
|
||||
AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
|
||||
validateFallback(annotation.getClass("fallback"));
|
||||
validateFallbackFactory(annotation.getClass("fallbackFactory"));
|
||||
}
|
||||
|
||||
/* for testing */ String getName(Map<String, Object> attributes) {
|
||||
return getName(null, attributes);
|
||||
}
|
||||
|
||||
String getName(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
|
||||
String name = (String) attributes.get("serviceId");
|
||||
if (!StringUtils.hasText(name)) {
|
||||
name = (String) attributes.get("name");
|
||||
}
|
||||
if (!StringUtils.hasText(name)) {
|
||||
name = (String) attributes.get("value");
|
||||
}
|
||||
name = resolve(beanFactory, name);
|
||||
return getName(name);
|
||||
}
|
||||
|
||||
private String getContextId(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
|
||||
String contextId = (String) attributes.get("contextId");
|
||||
if (!StringUtils.hasText(contextId)) {
|
||||
return getName(attributes);
|
||||
}
|
||||
|
||||
contextId = resolve(beanFactory, contextId);
|
||||
return getName(contextId);
|
||||
}
|
||||
|
||||
private String resolve(ConfigurableBeanFactory beanFactory, String value) {
|
||||
if (StringUtils.hasText(value)) {
|
||||
if (beanFactory == null) {
|
||||
return this.environment.resolvePlaceholders(value);
|
||||
}
|
||||
BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();
|
||||
String resolved = beanFactory.resolveEmbeddedValue(value);
|
||||
if (resolver == null) {
|
||||
return resolved;
|
||||
}
|
||||
Object evaluateValue = resolver.evaluate(resolved, new BeanExpressionContext(beanFactory, null));
|
||||
if (evaluateValue != null) {
|
||||
return String.valueOf(evaluateValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String getUrl(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
|
||||
String url = resolve(beanFactory, (String) attributes.get("url"));
|
||||
return getUrl(url);
|
||||
}
|
||||
|
||||
private String getPath(ConfigurableBeanFactory beanFactory, Map<String, Object> attributes) {
|
||||
String path = resolve(beanFactory, (String) attributes.get("path"));
|
||||
return getPath(path);
|
||||
}
|
||||
|
||||
protected ClassPathScanningCandidateComponentProvider getScanner() {
|
||||
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
|
||||
@Override
|
||||
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
|
||||
boolean isCandidate = false;
|
||||
if (beanDefinition.getMetadata().isIndependent()) {
|
||||
if (!beanDefinition.getMetadata().isAnnotation()) {
|
||||
isCandidate = true;
|
||||
}
|
||||
}
|
||||
return isCandidate;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
|
||||
Map<String, Object> attributes = importingClassMetadata
|
||||
.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());
|
||||
|
||||
Set<String> basePackages = new HashSet<>();
|
||||
for (String pkg : (String[]) attributes.get("value")) {
|
||||
if (StringUtils.hasText(pkg)) {
|
||||
basePackages.add(pkg);
|
||||
}
|
||||
}
|
||||
for (String pkg : (String[]) attributes.get("basePackages")) {
|
||||
if (StringUtils.hasText(pkg)) {
|
||||
basePackages.add(pkg);
|
||||
}
|
||||
}
|
||||
for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
|
||||
basePackages.add(ClassUtils.getPackageName(clazz));
|
||||
}
|
||||
|
||||
if (basePackages.isEmpty()) {
|
||||
basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
|
||||
}
|
||||
return basePackages;
|
||||
}
|
||||
|
||||
private String getQualifier(Map<String, Object> client) {
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
String qualifier = (String) client.get("qualifier");
|
||||
if (StringUtils.hasText(qualifier)) {
|
||||
return qualifier;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] getQualifiers(Map<String, Object> client) {
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
List<String> qualifierList = new ArrayList<>(Arrays.asList((String[]) client.get("qualifiers")));
|
||||
qualifierList.removeIf(qualifier -> !StringUtils.hasText(qualifier));
|
||||
if (qualifierList.isEmpty() && getQualifier(client) != null) {
|
||||
qualifierList = Collections.singletonList(getQualifier(client));
|
||||
}
|
||||
return !qualifierList.isEmpty() ? qualifierList.toArray(new String[0]) : null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method registers beans definition with refreshScope.
|
||||
*
|
||||
* @param registry spring bean definition registry
|
||||
* @param contextId name of feign client
|
||||
* @param beanType type of bean
|
||||
* @param factoryBeanType points to a relevant bean factory
|
||||
*/
|
||||
private void registerRefreshableBeanDefinition(BeanDefinitionRegistry registry, String contextId, Class<?> beanType,
|
||||
Class<?> factoryBeanType) {
|
||||
if (isClientRefreshEnabled()) {
|
||||
String beanName = beanType.getCanonicalName() + "-" + contextId;
|
||||
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(factoryBeanType);
|
||||
definitionBuilder.setScope("refresh");
|
||||
definitionBuilder.addPropertyValue("contextId", contextId);
|
||||
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(definitionBuilder.getBeanDefinition(),
|
||||
beanName);
|
||||
definitionHolder = ScopedProxyUtils.createScopedProxy(definitionHolder, registry, true);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isClientRefreshEnabled() {
|
||||
return environment.getProperty("spring.cloud.openfeign.client.refresh-enabled", Boolean.class, false);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
-- ----------------------------
|
||||
-- Table structure for tenant_info
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `tenant_info`;
|
||||
CREATE TABLE `tenant_info`
|
||||
(
|
||||
`id` bigint NOT NULL COMMENT '租户ID',
|
||||
`domain` varchar(255) NOT NULL COMMENT '二级域名',
|
||||
`account` varchar(255) NOT NULL COMMENT '管理员账号',
|
||||
`pwd` varchar(255) NOT NULL COMMENT '管理员密码',
|
||||
`company` varchar(255) DEFAULT NULL COMMENT '租户公司',
|
||||
`create_time` bigint NOT NULL COMMENT '创建时间',
|
||||
`update_time` bigint DEFAULT NULL COMMENT '修改时间',
|
||||
`enable` tinyint(1) NOT NULL COMMENT '是否可用',
|
||||
`deleted` tinyint(1) NOT NULL COMMENT '是否已删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for tenant_db
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `tenant_db`;
|
||||
CREATE TABLE `tenant_db`
|
||||
(
|
||||
`id` bigint NOT NULL COMMENT '数据源ID',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`url` varchar(255) NOT NULL COMMENT 'jdbcurl',
|
||||
`username` varchar(255) NOT NULL COMMENT 'db用户',
|
||||
`pwd` varchar(255) NOT NULL COMMENT 'db密码',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
@@ -15,7 +15,6 @@
|
||||
<modules>
|
||||
<module>common</module>
|
||||
<module>api</module>
|
||||
<module>distributed</module>
|
||||
<module>extensions</module>
|
||||
</modules>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user