feat: 对于springboot和solon的适配调整

This commit is contained in:
阿杰 2025-01-07 22:27:44 +08:00
parent c23ea6b136
commit 8176c53a78
28 changed files with 291 additions and 1103 deletions

View File

@ -20,7 +20,7 @@
<dependencies>
<dependency>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-core</artifactId>
<artifactId>easy-es-spring</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -0,0 +1,85 @@
package org.dromara.easyes.starter;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.core.service.AutoProcessIndexService;
import org.dromara.easyes.spring.factory.IndexStrategyFactory;
import org.dromara.easyes.spring.index.AutoProcessIndexNotSmoothlyServiceImpl;
import org.dromara.easyes.spring.index.AutoProcessIndexSmoothlyServiceImpl;
import org.dromara.easyes.common.property.EasyEsDynamicProperties;
import org.dromara.easyes.common.property.EasyEsProperties;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import java.util.*;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
/**
* es自动配置
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Configuration
@ConditionalOnClass(RestHighLevelClient.class)
@ConditionalOnExpression("'${easy-es.address:x}'!='x'")
@ConditionalOnProperty(prefix = "easy-es", name = {"enable"}, havingValue = "true", matchIfMissing = true)
public class EsAutoConfiguration {
/**
* 装配RestHighLevelClient
*
* @return RestHighLevelClient bean
*/
@Bean
@ConditionalOnMissingBean
public RestHighLevelClient restHighLevelClient() {
return RestHighLevelClientUtils.restHighLevelClient(easyEsProperties());
}
@Bean
@ConfigurationProperties(prefix = "easy-es")
public EasyEsProperties easyEsProperties() {
return new EasyEsProperties();
}
@Bean
@ConfigurationProperties(prefix = "easy-es.dynamic")
public EasyEsDynamicProperties easyEsDynamicProperties() {
return new EasyEsDynamicProperties();
}
@Bean
public IndexStrategyFactory indexStrategyFactory() {
return new IndexStrategyFactory();
}
@Bean
public AutoProcessIndexService autoProcessIndexSmoothlyServiceImpl() {
return new AutoProcessIndexSmoothlyServiceImpl();
}
@Bean
public AutoProcessIndexService autoProcessIndexNotSmoothlyServiceImpl() {
return new AutoProcessIndexNotSmoothlyServiceImpl();
}
}

View File

@ -1,20 +0,0 @@
package org.dromara.easyes.starter.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.HashMap;
import java.util.Map;
/**
* @author lyy
*/
@Data
@ConfigurationProperties(prefix = "easy-es.dynamic")
public class DynamicEsProperties {
/**
* 配置多动态数据源key datasource id
*/
private Map<String, EasyEsConfigProperties> datasource = new HashMap<>();
}

View File

@ -1,138 +0,0 @@
package org.dromara.easyes.starter.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.utils.*;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import java.util.*;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
import static org.dromara.easyes.common.utils.RestHighLevelClientUtils.DEFAULT_DS;
/**
* es自动配置
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Configuration
@ConditionalOnClass(RestHighLevelClient.class)
@EnableConfigurationProperties(value = {DynamicEsProperties.class, EasyEsConfigProperties.class})
@ConditionalOnProperty(prefix = "easy-es", name = {"enable"}, havingValue = "true", matchIfMissing = true)
public class EsAutoConfiguration {
@Autowired
private EasyEsConfigProperties easyEsConfigProperties;
@Autowired
private DynamicEsProperties dynamicEsProperties;
/**
* 装配RestHighLevelClient
*
* @return RestHighLevelClient bean
*/
@Bean
@ConditionalOnMissingBean
public RestHighLevelClient restHighLevelClient() {
return restHighLevelClient(easyEsConfigProperties);
}
@Bean
public RestHighLevelClientUtils restHighLevelClientUtils() {
RestHighLevelClientUtils restHighLevelClientUtils = new RestHighLevelClientUtils();
Map<String, EasyEsConfigProperties> datasourceMap = dynamicEsProperties.getDatasource();
if (CollectionUtils.isEmpty(datasourceMap)) {
// 设置默认数据源,兼容不使用多数据源配置场景的老用户使用习惯
datasourceMap.put(DEFAULT_DS, easyEsConfigProperties);
}
for (String key : datasourceMap.keySet()) {
EasyEsConfigProperties easyEsConfigProperties = datasourceMap.get(key);
RestHighLevelClientUtils.registerRestHighLevelClient(key, restHighLevelClient(easyEsConfigProperties));
}
return restHighLevelClientUtils;
}
private RestHighLevelClient restHighLevelClient(EasyEsConfigProperties easyEsConfigProperties) {
// 处理地址
String address = easyEsConfigProperties.getAddress();
if (StringUtils.isEmpty(address)) {
throw ExceptionUtils.eee("please config the es address");
}
if (!address.contains(COLON)) {
throw ExceptionUtils.eee("the address must contains port and separate by ':'");
}
String schema = StringUtils.isEmpty(easyEsConfigProperties.getSchema())
? DEFAULT_SCHEMA : easyEsConfigProperties.getSchema();
List<HttpHost> hostList = new ArrayList<>();
Arrays.stream(easyEsConfigProperties.getAddress().split(COMMA))
.forEach(item -> hostList.add(new HttpHost(item.split(COLON)[0],
Integer.parseInt(item.split(COLON)[1]), schema)));
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostList.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
builder.setHttpClientConfigCallback(httpClientBuilder -> {
// 设置心跳时间,最大连接数,最大连接路由
Optional.ofNullable(easyEsConfigProperties.getKeepAliveMillis()).ifPresent(p -> httpClientBuilder.setKeepAliveStrategy((response, context) -> p));
Optional.ofNullable(easyEsConfigProperties.getMaxConnTotal()).ifPresent(httpClientBuilder::setMaxConnTotal);
Optional.ofNullable(easyEsConfigProperties.getMaxConnPerRoute()).ifPresent(httpClientBuilder::setMaxConnPerRoute);
// 设置账号密码
String username = easyEsConfigProperties.getUsername();
String password = easyEsConfigProperties.getPassword();
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
// https ssl ignore
if (SchemaEnum.https.name().equals(schema)) {
try {
// 信任所有
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);
httpClientBuilder.disableAuthCaching();
httpClientBuilder.setSSLStrategy(sessionStrategy);
} catch (Exception e) {
LogUtils.error("restHighLevelClient build SSLContext exception: %s", e.getMessage());
e.printStackTrace();
throw ExceptionUtils.eee(e);
}
}
return httpClientBuilder;
});
// 设置超时时间之类的
builder.setRequestConfigCallback(requestConfigBuilder -> {
Optional.ofNullable(easyEsConfigProperties.getConnectTimeout()).ifPresent(requestConfigBuilder::setConnectTimeout);
Optional.ofNullable(easyEsConfigProperties.getSocketTimeout()).ifPresent(requestConfigBuilder::setSocketTimeout);
Optional.ofNullable(easyEsConfigProperties.getConnectionRequestTimeout())
.ifPresent(requestConfigBuilder::setConnectionRequestTimeout);
return requestConfigBuilder;
});
return new RestHighLevelClient(builder);
}
}

View File

@ -1,70 +0,0 @@
package org.dromara.easyes.starter.factory;
import org.dromara.easyes.starter.config.EasyEsConfigProperties;
import org.dromara.easyes.starter.service.AutoProcessIndexService;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.ExceptionUtils;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* 自动托管索引策略工厂
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Component
@ConditionalOnClass(RestHighLevelClient.class)
@ConditionalOnProperty(prefix = "easy-es", name = {"enable"}, havingValue = "true", matchIfMissing = true)
public class IndexStrategyFactory implements ApplicationContextAware, InitializingBean {
/**
* 配置
*/
@Autowired
private EasyEsConfigProperties esConfigProperties;
/**
* 预估初始策略工厂容量
*/
private static final Integer DEFAULT_SIZE = 4;
/**
* spring上下文
*/
private ApplicationContext applicationContext;
/**
* 策略容器
*/
private static final Map<Integer, AutoProcessIndexService> SERVICE_MAP = new HashMap<>(DEFAULT_SIZE);
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
// 是否开启自动托管模式,默认开启
if (!ProcessIndexStrategyEnum.MANUAL.equals(esConfigProperties.getGlobalConfig().getProcessIndexMode())) {
// 将bean注册进工厂
applicationContext.getBeansOfType(AutoProcessIndexService.class)
.values()
.forEach(v -> SERVICE_MAP.putIfAbsent(v.getStrategyType(), v));
}
}
public AutoProcessIndexService getByStrategyType(Integer strategyType) {
return Optional.ofNullable(SERVICE_MAP.get(strategyType))
.orElseThrow(() -> ExceptionUtils.eee("no such service strategyType:{}", strategyType));
}
}

View File

@ -1,95 +0,0 @@
package org.dromara.easyes.starter.register;
import org.dromara.easyes.core.kernel.BaseEsMapper;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import java.util.Arrays;
import java.util.Set;
/**
* 扫描指定路径下的所有接口
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
public void registerFilters() {
// default include filter that accepts all classes
addIncludeFilter((metadataReader, metadataReaderFactory) -> {
// 跳过非ee的mapper,比如瞎几把写的接口,没有继承BaseEsMapper
String className = metadataReader.getClassMetadata().getClassName();
try {
Class<?> clazz = Class.forName(className);
return BaseEsMapper.class.isAssignableFrom(clazz);
} catch (ClassNotFoundException e) {
logger.debug("mapper not found" + e);
}
return true;
});
// exclude package-info.java
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No Easy-Es mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + beanClassName + "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
definition.setBeanClass(MapperFactoryBean.class);
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
/**
* {@inheritDoc}
*/
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
logger.warn("Skipping MapperFactoryBean with name '" + beanName
+ "' and '" + beanDefinition.getBeanClassName() + "' mapperInterface"
+ ". Bean already defined with the same name!");
return false;
}
}
}

View File

@ -1,19 +0,0 @@
package org.dromara.easyes.starter.register;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* 全局Mapper扫描注解
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MapperScannerRegister.class)
public @interface EsMapperScan {
String value();
}

View File

@ -1,129 +0,0 @@
package org.dromara.easyes.starter.register;
import org.dromara.easyes.annotation.EsDS;
import org.dromara.easyes.annotation.Intercepts;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.common.utils.RestHighLevelClientUtils;
import org.dromara.easyes.common.utils.TypeUtils;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.cache.BaseCache;
import org.dromara.easyes.core.cache.GlobalConfigCache;
import org.dromara.easyes.common.property.GlobalConfig;
import org.dromara.easyes.core.proxy.EsMapperProxy;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.extension.context.Interceptor;
import org.dromara.easyes.extension.context.InterceptorChain;
import org.dromara.easyes.extension.context.InterceptorChainHolder;
import org.dromara.easyes.starter.config.EasyEsConfigProperties;
import org.dromara.easyes.starter.factory.IndexStrategyFactory;
import org.dromara.easyes.starter.service.AutoProcessIndexService;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import static org.dromara.easyes.common.constants.BaseEsConstants.ZERO;
import static org.dromara.easyes.common.utils.RestHighLevelClientUtils.DEFAULT_DS;
/**
* 代理类
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public class MapperFactoryBean<T> implements FactoryBean<T> {
private Class<T> mapperInterface;
@Autowired
private RestHighLevelClientUtils restHighLevelClientUtils;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private IndexStrategyFactory indexStrategyFactory;
@Autowired
private EasyEsConfigProperties esConfigProperties;
public MapperFactoryBean() {
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
@Override
public T getObject() throws Exception {
EsMapperProxy<T> esMapperProxy = new EsMapperProxy<>(mapperInterface, new ConcurrentHashMap<>());
// 获取实体类
Class<?> entityClass = TypeUtils.getInterfaceT(mapperInterface, ZERO);
// 初始化缓存
GlobalConfigCache.setGlobalConfig(esConfigProperties.getGlobalConfig());
//获取动态数据源 若未配置多数据源,则使用默认数据源
String restHighLevelClientId = Optional.ofNullable(mapperInterface.getAnnotation(EsDS.class)).map(EsDS::value).orElse(DEFAULT_DS);
RestHighLevelClient client = restHighLevelClientUtils.getClient(restHighLevelClientId);
BaseCache.initCache(mapperInterface, entityClass, client);
// 创建代理
T t = (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[]{mapperInterface}, esMapperProxy);
// 初始化拦截器链
InterceptorChain interceptorChain = this.initInterceptorChain();
// 异步处理索引创建/更新/数据迁移等
GlobalConfig globalConfig = esConfigProperties.getGlobalConfig();
if (!ProcessIndexStrategyEnum.MANUAL.equals(globalConfig.getProcessIndexMode())) {
// 父子类型,仅针对父类型创建索引,子类型不创建索引
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
boolean isChild = entityInfo.isChild();
if (!isChild) {
AutoProcessIndexService autoProcessIndexService = indexStrategyFactory
.getByStrategyType(globalConfig.getProcessIndexMode().getStrategyType());
autoProcessIndexService.processIndexAsync(entityClass, client);
}
} else {
LogUtils.info("===> manual index mode activated");
}
return interceptorChain.pluginAll(t);
}
@Override
public Class<?> getObjectType() {
return this.mapperInterface;
}
@Override
public boolean isSingleton() {
return true;
}
private InterceptorChain initInterceptorChain() {
InterceptorChainHolder interceptorChainHolder = InterceptorChainHolder.getInstance();
InterceptorChain interceptorChain = interceptorChainHolder.getInterceptorChain();
if (interceptorChain == null) {
synchronized (this) {
interceptorChainHolder.initInterceptorChain();
Map<String, Object> beansWithAnnotation = this.applicationContext.getBeansWithAnnotation(Intercepts.class);
beansWithAnnotation.forEach((key, val) -> {
if (val instanceof Interceptor) {
Interceptor interceptor = (Interceptor) val;
interceptorChainHolder.addInterceptor(interceptor);
}
});
}
}
return interceptorChainHolder.getInterceptorChain();
}
}

View File

@ -1,137 +0,0 @@
package org.dromara.easyes.starter.register;
import org.dromara.easyes.common.utils.EEVersionUtils;
import org.dromara.easyes.common.utils.LogUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
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.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
/**
* 注册bean
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
public class MapperScannerRegister implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Boolean enable = Optional.ofNullable(environment.getProperty(ENABLE_PREFIX)).map(Boolean::parseBoolean).orElse(Boolean.TRUE);
if (!enable) {
LogUtils.info("===> Easy-Es is not enabled");
return;
}
//打印banner @author dazer007
boolean banner = Optional.ofNullable(environment.getProperty(ENABLE_BANNER)).map(Boolean::parseBoolean).orElse(Boolean.TRUE);
if (banner) {
boolean iKunMode = Optional.ofNullable(environment.getProperty(ENABLE_I_KUN_MODE)).map(Boolean::parseBoolean).orElse(Boolean.FALSE);
String versionStr = EEVersionUtils.getJarVersion(this.getClass());
String wechatStr = ":: wechat :: 252645816, add and become muscle man! >";
if (iKunMode) {
System.out.println(" 鸡你太美\n" +
" 鸡你实在太美\n" +
" 鸡你是太美\n" +
" 鸡你太美\n" +
" 实在是太美鸡你\n" +
" 鸡你 实在是太美鸡你 美\n" +
" 鸡你 实在是太美鸡美 太美\n" +
" 鸡你 实在是太美鸡美 太美\n" +
" 鸡你 实在是太美鸡美 太美\n" +
" 鸡你 鸡你实在是美太美 美蓝球球球\n" +
"鸡 鸡 鸡你实在是太美 篮球篮球球球球\n" +
" 鸡 鸡你太美裆鸡太啊 球球蓝篮球球\n" +
" 鸡你太美裆裆鸡美 球球球\n" +
" 鸡你裆小 j 鸡太美\n" +
" 鸡太美 鸡太美\n" +
" 鸡美 鸡美\n" +
" 鸡美 鸡美\n" +
" 鸡美 鸡美\n" +
" 鸡太 鸡太\n" +
" 鸡 脚 鸡脚\n" +
" 皮 鞋 皮鞋金猴\n" +
" 金光 金光 大道\n" +
" 大道\n" +
" 鸡神保佑 永不宕机 永无BUG");
wechatStr = ":: wechat :: 252645816, add and join ikun(小黑子) group! >";
} else {
System.out.println("\n" +
"___ _ _ ___\n" +
" | __| __ _ ___ | || | ___ | __| ___\n" +
" | _| / _` | (_-< \\_, | |___| | _| (_-<\n" +
" |___| \\__,_| /__/_ _|__/ _____ |___| /__/_\n" +
"_|\"\"\"\"\"|_|\"\"\"\"\"|_|\"\"\"\"\"|_| \"\"\"\"|_| |_|\"\"\"\"\"|_|\"\"\"\"\"|\n" +
"\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\"`-0-0-'\n" +
"----------------------------------------------------------->"
);
}
// 版本长度并不固定,比如beta版,所以需要特殊处理
int width = 43;
int blank = width - versionStr.length();
StringBuilder sb = new StringBuilder();
sb.append(":: version :: ")
.append(versionStr);
for (int i = 0; i < blank; i++) {
sb.append(" ");
}
sb.append(">");
if (iKunMode) {
System.out.println("----------------------------------------------------------->");
}
System.out.println(":: project :: Easy-Es >");
System.out.println(sb);
System.out.println(":: home :: https://easy-es.cn/ >");
System.out.println(":: community :: https://dromara.org/ >");
System.out.println(wechatStr);
System.out.println("----------------------------------------------------------->");
}
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(EsMapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(mapperScanAttrs, registry);
}
}
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// this check is needed in Spring 3.1
Optional.ofNullable(resourceLoader).ifPresent(scanner::setResourceLoader);
List<String> basePackages = new ArrayList<>();
basePackages.addAll(
Arrays.stream(annoAttrs.getStringArray("value"))
.filter(StringUtils::hasText)
.collect(Collectors.toList()));
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}

View File

@ -1,25 +0,0 @@
package org.dromara.easyes.starter.service;
import org.elasticsearch.client.RestHighLevelClient;
/**
* 自动托管索引接口
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
public interface AutoProcessIndexService {
/**
* 获取当前策略类型
*
* @return 策略类型
*/
Integer getStrategyType();
/**
* 异步处理索引
*
* @param entityClass 实体类
* @param client restHighLevelClient
*/
void processIndexAsync(Class<?> entityClass, RestHighLevelClient client);
}

View File

@ -1,85 +0,0 @@
package org.dromara.easyes.starter.service.impl;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.core.biz.CreateIndexParam;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.EsIndexInfo;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.core.toolkit.IndexUtils;
import org.dromara.easyes.starter.service.AutoProcessIndexService;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
/**
* 自动非平滑托管索引实现类, 重建索引时原索引数据会被删除
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Service
@ConditionalOnClass(RestHighLevelClient.class)
@ConditionalOnExpression("'${easy-es.address:x}'!='x'")
@ConditionalOnProperty(prefix = "easy-es", name = {"enable"}, havingValue = "true", matchIfMissing = true)
public class AutoProcessIndexNotSmoothlyServiceImpl implements AutoProcessIndexService {
@Override
public Integer getStrategyType() {
return ProcessIndexStrategyEnum.NOT_SMOOTHLY.getStrategyType();
}
@Override
public void processIndexAsync(Class<?> entityClass, RestHighLevelClient client) {
LogUtils.info("===> Not smoothly process index mode activated");
IndexUtils.supplyAsync(this::process, entityClass, client);
}
private boolean process(Class<?> entityClass, RestHighLevelClient client) {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
// 是否存在索引
boolean existsIndex = IndexUtils.existsIndexWithRetry(entityInfo, client);
if (existsIndex) {
// 更新
LogUtils.info("===> Index exists, automatically updating index by easy-es...");
return doUpdateIndex(entityInfo, entityClass, client);
} else {
// 新建
LogUtils.info("===> Index not exists, automatically creating index by easy-es...");
return doCreateIndex(entityInfo, entityClass, client);
}
}
private boolean doUpdateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 获取索引信息
EsIndexInfo esIndexInfo = IndexUtils.getIndexInfo(client, entityInfo.getRetrySuccessIndexName());
// 索引是否有变化 若有则直接删除旧索引,创建新索引 若无则直接返回托管成功
boolean isIndexNeedChange = IndexUtils.isIndexNeedChange(esIndexInfo, entityInfo, clazz);
if (!isIndexNeedChange) {
LogUtils.info("===> index has nothing changed");
entityInfo.setIndexName(entityInfo.getRetrySuccessIndexName());
return Boolean.TRUE;
}
// 直接删除旧索引
IndexUtils.deleteIndex(client, entityInfo.getRetrySuccessIndexName());
// 初始化创建索引参数
CreateIndexParam createIndexParam = IndexUtils.getCreateIndexParam(entityInfo, clazz);
// 执行创建
return IndexUtils.createIndex(client, entityInfo, createIndexParam);
}
private boolean doCreateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 初始化创建索引参数
CreateIndexParam createIndexParam = IndexUtils.getCreateIndexParam(entityInfo, clazz);
// 执行创建
return IndexUtils.createIndex(client, entityInfo, createIndexParam);
}
}

View File

@ -1,136 +0,0 @@
package org.dromara.easyes.starter.service.impl;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.core.biz.CreateIndexParam;
import org.dromara.easyes.core.biz.EntityInfo;
import org.dromara.easyes.core.biz.EsIndexInfo;
import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.core.toolkit.IndexUtils;
import org.dromara.easyes.starter.service.AutoProcessIndexService;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import static org.dromara.easyes.common.constants.BaseEsConstants.S1_SUFFIX;
import static org.dromara.easyes.common.constants.BaseEsConstants.SO_SUFFIX;
/**
* 自动平滑托管索引实现类,本框架默认模式,过程零停机,数据会自动转移至新索引
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Service
@ConditionalOnClass(RestHighLevelClient.class)
@ConditionalOnExpression("'${easy-es.address:x}'!='x'")
@ConditionalOnProperty(prefix = "easy-es", name = {"enable"}, havingValue = "true", matchIfMissing = true)
public class AutoProcessIndexSmoothlyServiceImpl implements AutoProcessIndexService {
@Override
public Integer getStrategyType() {
return ProcessIndexStrategyEnum.SMOOTHLY.getStrategyType();
}
@Override
public void processIndexAsync(Class<?> entityClass, RestHighLevelClient client) {
LogUtils.info("===> Smoothly process index mode activated");
IndexUtils.supplyAsync(this::process, entityClass, client);
}
private synchronized boolean process(Class<?> entityClass, RestHighLevelClient client) {
EntityInfo entityInfo = EntityInfoHelper.getEntityInfo(entityClass);
// 索引是否已存在
boolean existsIndex = IndexUtils.existsIndexWithRetryAndSetActiveIndex(entityInfo, client);
if (existsIndex) {
// 更新
LogUtils.info("===> Index exists, automatically updating index by easy-es...");
return doUpdateIndex(entityInfo, entityClass, client);
} else {
// 新建
LogUtils.info("===> Index not exists, automatically creating index by easy-es...");
return doCreateIndex(entityInfo, entityClass, client);
}
}
private boolean doUpdateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 获取索引信息
EsIndexInfo esIndexInfo = IndexUtils.getIndexInfo(client, entityInfo.getIndexName());
// 是否存在默认别名,若无则给添加
if (!esIndexInfo.getHasDefaultAlias()) {
IndexUtils.addDefaultAlias(client, entityInfo.getIndexName());
}
// 索引是否有变化 若有则创建新索引并无感迁移, 若无则直接返回托管成功
boolean isIndexNeedChange = IndexUtils.isIndexNeedChange(esIndexInfo, entityInfo, clazz);
if (!isIndexNeedChange) {
LogUtils.info("===> index has nothing changed");
return Boolean.TRUE;
}
// 创建新索引
String releaseIndexName = generateReleaseIndexName(entityInfo.getIndexName());
entityInfo.setReleaseIndexName(releaseIndexName);
boolean isCreateIndexSuccess = doCreateIndex(entityInfo, clazz, client);
if (!isCreateIndexSuccess) {
LogUtils.error("create release index failed", "releaseIndex:" + releaseIndexName);
return Boolean.FALSE;
}
// 迁移数据至新创建的索引
boolean isDataMigrationSuccess = doDataMigration(entityInfo.getIndexName(), releaseIndexName, entityInfo.getMaxResultWindow(), client);
if (!isDataMigrationSuccess) {
LogUtils.error("migrate data failed", "oldIndex:" + entityInfo.getIndexName(), "releaseIndex:" + releaseIndexName);
return Boolean.FALSE;
}
// 原子操作 切换别名:将默认别名关联至新索引,并将旧索引的默认别名移除
boolean isChangeAliasSuccess = IndexUtils.changeAliasAtomic(client, entityInfo.getIndexName(), releaseIndexName);
if (!isChangeAliasSuccess) {
LogUtils.error("change alias atomically failed", "oldIndex:" + entityInfo.getIndexName(), "releaseIndex:" + releaseIndexName);
return Boolean.FALSE;
}
// 删除旧索引
boolean isDeletedIndexSuccess = IndexUtils.deleteIndex(client, entityInfo.getIndexName());
if (!isDeletedIndexSuccess) {
LogUtils.error("delete old index failed", "oldIndex:" + entityInfo.getIndexName());
return Boolean.FALSE;
}
// 用最新索引覆盖缓存中的老索引
entityInfo.setIndexName(releaseIndexName);
// 将新索引名称记录至ee-distribute-lock索引中,以便在分布式环境下其它机器能够感知到
IndexUtils.saveReleaseIndex(releaseIndexName, client);
// done.
return Boolean.TRUE;
}
private String generateReleaseIndexName(String oldIndexName) {
if (oldIndexName.endsWith(SO_SUFFIX)) {
return oldIndexName.split(SO_SUFFIX)[0] + S1_SUFFIX;
} else if (oldIndexName.endsWith(S1_SUFFIX)) {
return oldIndexName.split(S1_SUFFIX)[0] + SO_SUFFIX;
} else {
return oldIndexName + SO_SUFFIX;
}
}
private boolean doDataMigration(String oldIndexName, String releaseIndexName, Integer maxResultWindow, RestHighLevelClient client) {
return IndexUtils.reindex(client, oldIndexName, releaseIndexName, maxResultWindow);
}
private boolean doCreateIndex(EntityInfo entityInfo, Class<?> clazz, RestHighLevelClient client) {
// 初始化创建索引参数
CreateIndexParam createIndexParam = IndexUtils.getCreateIndexParam(entityInfo, clazz);
// 执行创建
return IndexUtils.createIndex(client, entityInfo, createIndexParam);
}
}

View File

@ -1,7 +1,4 @@
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.dromara.easyes.starter.config.EsAutoConfiguration,\
org.dromara.easyes.starter.factory.IndexStrategyFactory,\
org.dromara.easyes.starter.service.impl.AutoProcessIndexSmoothlyServiceImpl,\
org.dromara.easyes.starter.service.impl.AutoProcessIndexNotSmoothlyServiceImpl,\
org.dromara.easyes.starter.EsAutoConfiguration,\
org.dromara.easyes.starter.config.GeneratorConfiguration

View File

@ -1,5 +1 @@
org.dromara.easyes.starter.config.EsAutoConfiguration
org.dromara.easyes.starter.factory.IndexStrategyFactory
org.dromara.easyes.starter.service.impl.AutoProcessIndexSmoothlyServiceImpl
org.dromara.easyes.starter.service.impl.AutoProcessIndexNotSmoothlyServiceImpl
org.dromara.easyes.starter.config.GeneratorConfiguration
org.dromara.easyes.starter.EsAutoConfiguration

View File

@ -0,0 +1,21 @@
package org.dromara.easyes.common.property;
import lombok.Data;
import java.util.*;
/**
* easy-es基础配置项 考虑到spring的场景有些参数不是必须配置
* 基本类型就会出现默认值的情况 所以为了要有null值出现这里采用包装类型
* <p>
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Data
public class EasyEsDynamicProperties {
/**
* 配置多动态数据源key datasource id
*/
private Map<String, EasyEsProperties> datasource = new HashMap<>();
}

View File

@ -1,11 +1,7 @@
package org.dromara.easyes.solon.config;
package org.dromara.easyes.common.property;
import lombok.Data;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.property.GlobalConfig;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
/**
* easy-es基础配置项
@ -13,10 +9,8 @@ import org.noear.solon.annotation.Inject;
* Copyright © 2022 xpc1024 All Rights Reserved
**/
@Data
@Configuration
@Inject(value = "${easy-es}", autoRefreshed = true)
@Condition(onProperty = "${easy-es.enable:true} = true && ${easy-es.address:x} != x")
public class EasyEsConfigProperties {
public class EasyEsProperties {
/**
* 是否开启easy-es 默认开启
*/
@ -69,4 +63,5 @@ public class EasyEsConfigProperties {
* global config 全局配置
*/
private GlobalConfig globalConfig = new GlobalConfig();
}

View File

@ -1,10 +1,27 @@
package org.dromara.easyes.common.utils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.property.EasyEsProperties;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import java.util.Map;
import javax.net.ssl.SSLContext;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
import static org.dromara.easyes.common.constants.BaseEsConstants.COLON;
/**
* @author lyy
*/
@ -40,4 +57,68 @@ public class RestHighLevelClientUtils {
RestHighLevelClientUtils.restHighLevelClientMap.putIfAbsent(restHighLevelClientId, restHighLevelClient);
}
public static RestHighLevelClient restHighLevelClient(EasyEsProperties easyEsConfigProperties) {
// 处理地址
String address = easyEsConfigProperties.getAddress();
if (StringUtils.isEmpty(address)) {
throw ExceptionUtils.eee("please config the es address");
}
if (!address.contains(COLON)) {
throw ExceptionUtils.eee("the address must contains port and separate by ':'");
}
String schema = StringUtils.isEmpty(easyEsConfigProperties.getSchema())
? DEFAULT_SCHEMA : easyEsConfigProperties.getSchema();
List<HttpHost> hostList = new ArrayList<>();
Arrays.stream(easyEsConfigProperties.getAddress().split(COMMA))
.forEach(item -> hostList.add(new HttpHost(item.split(COLON)[0],
Integer.parseInt(item.split(COLON)[1]), schema)));
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostList.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
builder.setHttpClientConfigCallback(httpClientBuilder -> {
// 设置心跳时间,最大连接数,最大连接路由
Optional.ofNullable(easyEsConfigProperties.getKeepAliveMillis()).ifPresent(p -> httpClientBuilder.setKeepAliveStrategy((response, context) -> p));
Optional.ofNullable(easyEsConfigProperties.getMaxConnTotal()).ifPresent(httpClientBuilder::setMaxConnTotal);
Optional.ofNullable(easyEsConfigProperties.getMaxConnPerRoute()).ifPresent(httpClientBuilder::setMaxConnPerRoute);
// 设置账号密码
String username = easyEsConfigProperties.getUsername();
String password = easyEsConfigProperties.getPassword();
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
// https ssl ignore
if (SchemaEnum.https.name().equals(schema)) {
try {
// 信任所有
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);
httpClientBuilder.disableAuthCaching();
httpClientBuilder.setSSLStrategy(sessionStrategy);
} catch (Exception e) {
LogUtils.error("restHighLevelClient build SSLContext exception: %s", e.getMessage());
e.printStackTrace();
throw ExceptionUtils.eee(e);
}
}
return httpClientBuilder;
});
// 设置超时时间之类的
builder.setRequestConfigCallback(requestConfigBuilder -> {
Optional.ofNullable(easyEsConfigProperties.getConnectTimeout()).ifPresent(requestConfigBuilder::setConnectTimeout);
Optional.ofNullable(easyEsConfigProperties.getSocketTimeout()).ifPresent(requestConfigBuilder::setSocketTimeout);
Optional.ofNullable(easyEsConfigProperties.getConnectionRequestTimeout())
.ifPresent(requestConfigBuilder::setConnectionRequestTimeout);
return requestConfigBuilder;
});
return new RestHighLevelClient(builder);
}
}

View File

@ -69,6 +69,11 @@
<artifactId>easy-es-annotation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dromara.easy-es</groupId>
<artifactId>easy-es-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>

View File

@ -1,23 +0,0 @@
package org.dromara.easyes.solon.config;
import lombok.Data;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import java.util.HashMap;
import java.util.Map;
/**
* @author lyy
*/
@Data
@Configuration
@Inject(value = "${easy-es.dynamic}", autoRefreshed = true)
public class DynamicEsProperties {
/**
* 配置多动态数据源key datasource id
*/
private Map<String, EasyEsConfigProperties> datasource = new HashMap<>();
}

View File

@ -1,30 +1,16 @@
package org.dromara.easyes.solon.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.apache.http.ssl.SSLContextBuilder;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.property.EasyEsDynamicProperties;
import org.dromara.easyes.common.property.EasyEsProperties;
import org.dromara.easyes.common.utils.*;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.noear.solon.annotation.Bean;
import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import javax.net.ssl.SSLContext;
import java.util.*;
import static org.dromara.easyes.common.constants.BaseEsConstants.*;
import static org.dromara.easyes.common.utils.RestHighLevelClientUtils.DEFAULT_DS;
/**
* es自动配置
* <p>
@ -34,10 +20,17 @@ import static org.dromara.easyes.common.utils.RestHighLevelClientUtils.DEFAULT_D
@Condition(onClass = RestHighLevelClient.class, onProperty = "${easy-es.enable:true} = true && ${easy-es.address:x} != x")
public class EsAutoConfiguration {
@Inject
private EasyEsConfigProperties easyEsConfigProperties;
@Inject
private DynamicEsProperties dynamicEsProperties;
@Bean
public EasyEsProperties easyEsProperties(
@Inject(value = "${easy-es}", autoRefreshed = true) EasyEsProperties properties) {
return properties;
}
@Bean
public EasyEsDynamicProperties easyEsDynamicProperties(
@Inject(value = "${easy-es.dynamic}", autoRefreshed = true) EasyEsDynamicProperties dynamicProperties) {
return dynamicProperties;
}
/**
* 装配RestHighLevelClient
@ -46,88 +39,25 @@ public class EsAutoConfiguration {
*/
@Bean
@Condition(onMissingBean = RestHighLevelClient.class)
public RestHighLevelClient restHighLevelClient() {
return restHighLevelClient(easyEsConfigProperties);
public RestHighLevelClient restHighLevelClient(EasyEsProperties easyEsProperties) {
return RestHighLevelClientUtils.restHighLevelClient(easyEsProperties);
}
@Bean
public RestHighLevelClientUtils restHighLevelClientUtils() {
public RestHighLevelClientUtils restHighLevelClientUtils(
EasyEsProperties properties, EasyEsDynamicProperties dynamicProperties) {
RestHighLevelClientUtils restHighLevelClientUtils = new RestHighLevelClientUtils();
Map<String, EasyEsConfigProperties> datasourceMap = dynamicEsProperties.getDatasource();
Map<String, EasyEsProperties> datasourceMap = dynamicProperties.getDatasource();
if (CollectionUtils.isEmpty(datasourceMap)) {
// 设置默认数据源,兼容不使用多数据源配置场景的老用户使用习惯
datasourceMap.put(DEFAULT_DS, easyEsConfigProperties);
datasourceMap.put(RestHighLevelClientUtils.DEFAULT_DS, properties);
}
for (String key : datasourceMap.keySet()) {
EasyEsConfigProperties easyEsConfigProperties = datasourceMap.get(key);
RestHighLevelClientUtils.registerRestHighLevelClient(key, restHighLevelClient(easyEsConfigProperties));
EasyEsProperties easyEsConfigProperties = datasourceMap.get(key);
RestHighLevelClientUtils.registerRestHighLevelClient(key, RestHighLevelClientUtils
.restHighLevelClient(easyEsConfigProperties));
}
return restHighLevelClientUtils;
}
private RestHighLevelClient restHighLevelClient(EasyEsConfigProperties easyEsConfigProperties) {
// 处理地址
String address = easyEsConfigProperties.getAddress();
if (StringUtils.isEmpty(address)) {
throw ExceptionUtils.eee("please config the es address");
}
if (!address.contains(COLON)) {
throw ExceptionUtils.eee("the address must contains port and separate by ':'");
}
String schema = StringUtils.isEmpty(easyEsConfigProperties.getSchema())
? DEFAULT_SCHEMA : easyEsConfigProperties.getSchema();
List<HttpHost> hostList = new ArrayList<>();
Arrays.stream(easyEsConfigProperties.getAddress().split(COMMA))
.forEach(item -> hostList.add(new HttpHost(item.split(COLON)[0],
Integer.parseInt(item.split(COLON)[1]), schema)));
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostList.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
builder.setHttpClientConfigCallback(httpClientBuilder -> {
// 设置心跳时间,最大连接数,最大连接路由
Optional.ofNullable(easyEsConfigProperties.getKeepAliveMillis()).ifPresent(p -> httpClientBuilder.setKeepAliveStrategy((response, context) -> p));
Optional.ofNullable(easyEsConfigProperties.getMaxConnTotal()).ifPresent(httpClientBuilder::setMaxConnTotal);
Optional.ofNullable(easyEsConfigProperties.getMaxConnPerRoute()).ifPresent(httpClientBuilder::setMaxConnPerRoute);
// 设置账号密码
String username = easyEsConfigProperties.getUsername();
String password = easyEsConfigProperties.getPassword();
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
// https ssl ignore
if (SchemaEnum.https.name().equals(schema)) {
try {
// 信任所有
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);
httpClientBuilder.disableAuthCaching();
httpClientBuilder.setSSLStrategy(sessionStrategy);
} catch (Exception e) {
LogUtils.error("restHighLevelClient build SSLContext exception: %s", e.getMessage());
throw ExceptionUtils.eee(e);
}
}
return httpClientBuilder;
});
// 设置超时时间之类的
builder.setRequestConfigCallback(requestConfigBuilder -> {
Optional.ofNullable(easyEsConfigProperties.getConnectTimeout()).ifPresent(requestConfigBuilder::setConnectTimeout);
Optional.ofNullable(easyEsConfigProperties.getSocketTimeout()).ifPresent(requestConfigBuilder::setSocketTimeout);
Optional.ofNullable(easyEsConfigProperties.getConnectionRequestTimeout())
.ifPresent(requestConfigBuilder::setConnectionRequestTimeout);
return requestConfigBuilder;
});
return new RestHighLevelClient(builder);
}
}

View File

@ -1,8 +1,8 @@
package org.dromara.easyes.solon.factory;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.property.EasyEsProperties;
import org.dromara.easyes.common.utils.ExceptionUtils;
import org.dromara.easyes.solon.config.EasyEsConfigProperties;
import org.dromara.easyes.solon.service.AutoProcessIndexService;
import org.elasticsearch.client.RestHighLevelClient;
import org.noear.solon.Solon;
@ -28,7 +28,7 @@ public class IndexStrategyFactory implements LifecycleBean {
* 配置
*/
@Inject
private EasyEsConfigProperties esConfigProperties;
private EasyEsProperties esConfigProperties;
/**
* 预估初始策略工厂容量
*/

View File

@ -11,5 +11,5 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EsMapperScan {
String value();
String[] value();
}

View File

@ -3,6 +3,7 @@ package org.dromara.easyes.solon.register;
import org.dromara.easyes.annotation.EsDS;
import org.dromara.easyes.annotation.Intercepts;
import org.dromara.easyes.common.enums.ProcessIndexStrategyEnum;
import org.dromara.easyes.common.property.EasyEsProperties;
import org.dromara.easyes.common.utils.EEVersionUtils;
import org.dromara.easyes.common.utils.LogUtils;
import org.dromara.easyes.common.utils.RestHighLevelClientUtils;
@ -17,7 +18,6 @@ import org.dromara.easyes.core.toolkit.EntityInfoHelper;
import org.dromara.easyes.extension.context.Interceptor;
import org.dromara.easyes.extension.context.InterceptorChain;
import org.dromara.easyes.extension.context.InterceptorChainHolder;
import org.dromara.easyes.solon.config.EasyEsConfigProperties;
import org.dromara.easyes.solon.factory.IndexStrategyFactory;
import org.dromara.easyes.solon.service.AutoProcessIndexService;
import org.elasticsearch.client.RestHighLevelClient;
@ -116,7 +116,8 @@ public class MapperScannerRegister implements BeanBuilder<EsMapperScan> {
System.out.println("----------------------------------------------------------->");
}
// 查找es mapper
Collection<Class<?>> classPath = ClassUtil.scanClasses(anno.value());
for (String doScan : anno.value()) {
Collection<Class<?>> classPath = ClassUtil.scanClasses(doScan);
for (Class<?> clazz : classPath) {
// 跳过非ee的mapper,比如瞎几把写的接口,没有继承BaseEsMapper继承了的推入容器
if (BaseEsMapper.class.isAssignableFrom(clazz)) {
@ -125,13 +126,15 @@ public class MapperScannerRegister implements BeanBuilder<EsMapperScan> {
}
}
}
/**
* 将mapper代理对象推入容器
* @param clazz mapper
* @author MoJie
*/
private void beanWrapPut(Class<?> clazz) {
EasyEsConfigProperties esConfigProperties = context.getBean(EasyEsConfigProperties.class);
EasyEsProperties esConfigProperties = context.getBean(EasyEsProperties.class);
RestHighLevelClientUtils restHighLevelClientUtils = context.getBeanOrNew(RestHighLevelClientUtils.class);
EsMapperProxy<?> esMapperProxy = new EsMapperProxy<>(clazz, new ConcurrentHashMap<>());
// 获取实体类

View File

@ -22,15 +22,13 @@ import java.util.Set;
* <p>
* Copyright © 2021 xpc1024 All Rights Reserved
**/
@Setter
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
@Setter
private IndexStrategyFactory indexStrategyFactory;
@Setter
private RestHighLevelClientUtils restHighLevelClientUtils;
@Setter
private GlobalConfig globalConfig;
public ClassPathMapperScanner(BeanDefinitionRegistry registry) {

View File

@ -13,7 +13,8 @@ import org.apache.http.ssl.SSLContextBuilder;
import org.dromara.easyes.common.enums.SchemaEnum;
import org.dromara.easyes.common.utils.*;
import org.dromara.easyes.spring.factory.IndexStrategyFactory;
import org.dromara.easyes.spring.property.EasyEsProperty;
import org.dromara.easyes.common.property.EasyEsDynamicProperties;
import org.dromara.easyes.common.property.EasyEsProperties;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
@ -57,6 +58,12 @@ public class MapperScannerConfigurer
@Setter
private RestHighLevelClientUtils restHighLevelClientUtils;
@Setter
private EasyEsProperties easyEsProperties = new EasyEsProperties();
@Setter
private EasyEsDynamicProperties easyEsDynamicProperties = new EasyEsDynamicProperties();
private ApplicationContext applicationContext;
private String beanName;
@ -93,19 +100,19 @@ public class MapperScannerConfigurer
scanner.registerFilters();
// 索引策略工厂 -- 需要spring 注册bean xml/component 注解方式均可
scanner.setIndexStrategyFactory(this.indexStrategyFactory);
EasyEsProperty easyEsProperty = new EasyEsProperty(this.getEnvironment());
scanner.setGlobalConfig(easyEsProperty.getGlobalConfig());
scanner.setGlobalConfig(easyEsProperties.getGlobalConfig());
// easy-es的连接对象注册 需要spring 注册bean xml/component 注解方式均可
if (this.restHighLevelClientUtils == null) {
RestHighLevelClientUtils restHighLevelClientUtils = new RestHighLevelClientUtils();
Map<String, EasyEsProperty> datasourceMap = easyEsProperty.getDatasource();
Map<String, EasyEsProperties> datasourceMap = this.easyEsDynamicProperties.getDatasource();
if (CollectionUtils.isEmpty(datasourceMap)) {
// 设置默认数据源,兼容不使用多数据源配置场景的老用户使用习惯
datasourceMap.put(RestHighLevelClientUtils.DEFAULT_DS, easyEsProperty);
datasourceMap.put(RestHighLevelClientUtils.DEFAULT_DS, easyEsProperties);
}
for (String key : datasourceMap.keySet()) {
EasyEsProperty easyEsConfigProperties = datasourceMap.get(key);
RestHighLevelClientUtils.registerRestHighLevelClient(key, restHighLevelClient(easyEsConfigProperties));
EasyEsProperties easyEsConfigProperties = datasourceMap.get(key);
RestHighLevelClientUtils.registerRestHighLevelClient(key, RestHighLevelClientUtils
.restHighLevelClient(easyEsConfigProperties));
}
this.restHighLevelClientUtils = restHighLevelClientUtils;
}
@ -233,83 +240,4 @@ public class MapperScannerConfigurer
}
}
private Map<String, Object> getDatasource() {
String dynamic = this.applicationContext.getEnvironment().getRequiredProperty("easy-es.dynamic");
Properties properties = new Properties();
Map<String, Object> map = new HashMap<>();
try {
properties.load(new java.io.StringReader(dynamic));
properties.forEach((key, value) -> map.put(key.toString(), value.toString()));
} catch (Exception e) {
// Handle exception
}
return map;
}
private static RestHighLevelClient restHighLevelClient(EasyEsProperty easyEsConfigProperties) {
// 处理地址
String address = easyEsConfigProperties.getAddress();
if (StringUtils.isEmpty(address)) {
throw ExceptionUtils.eee("please config the es address");
}
if (!address.contains(COLON)) {
throw ExceptionUtils.eee("the address must contains port and separate by ':'");
}
String schema = StringUtils.isEmpty(easyEsConfigProperties.getSchema())
? DEFAULT_SCHEMA : easyEsConfigProperties.getSchema();
List<HttpHost> hostList = new ArrayList<>();
Arrays.stream(easyEsConfigProperties.getAddress().split(COMMA))
.forEach(item -> hostList.add(new HttpHost(item.split(COLON)[0],
Integer.parseInt(item.split(COLON)[1]), schema)));
// 转换成 HttpHost 数组
HttpHost[] httpHost = hostList.toArray(new HttpHost[]{});
// 构建连接对象
RestClientBuilder builder = RestClient.builder(httpHost);
builder.setHttpClientConfigCallback(httpClientBuilder -> {
// 设置心跳时间,最大连接数,最大连接路由
Optional.ofNullable(easyEsConfigProperties.getKeepAliveMillis()).ifPresent(p -> httpClientBuilder.setKeepAliveStrategy((response, context) -> p));
Optional.ofNullable(easyEsConfigProperties.getMaxConnTotal()).ifPresent(httpClientBuilder::setMaxConnTotal);
Optional.ofNullable(easyEsConfigProperties.getMaxConnPerRoute()).ifPresent(httpClientBuilder::setMaxConnPerRoute);
// 设置账号密码
String username = easyEsConfigProperties.getUsername();
String password = easyEsConfigProperties.getPassword();
if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(password)) {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
// https ssl ignore
if (SchemaEnum.https.name().equals(schema)) {
try {
// 信任所有
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(sslContext, NoopHostnameVerifier.INSTANCE);
httpClientBuilder.disableAuthCaching();
httpClientBuilder.setSSLStrategy(sessionStrategy);
} catch (Exception e) {
LogUtils.error("restHighLevelClient build SSLContext exception: %s", e.getMessage());
e.printStackTrace();
throw ExceptionUtils.eee(e);
}
}
return httpClientBuilder;
});
// 设置超时时间之类的
builder.setRequestConfigCallback(requestConfigBuilder -> {
Optional.ofNullable(easyEsConfigProperties.getConnectTimeout()).ifPresent(requestConfigBuilder::setConnectTimeout);
Optional.ofNullable(easyEsConfigProperties.getSocketTimeout()).ifPresent(requestConfigBuilder::setSocketTimeout);
Optional.ofNullable(easyEsConfigProperties.getConnectionRequestTimeout())
.ifPresent(requestConfigBuilder::setConnectionRequestTimeout);
return requestConfigBuilder;
});
return new RestHighLevelClient(builder);
}
}

View File

@ -0,0 +1,34 @@
easy-es.keep-alive-millis=18000
easy-es.address=198.163.192.11:9200
easy-es.global-config.IKunMode=true
easy-es.global-config.process-index-mode=manual
easy-es.global-config.async-process-index-blocking=true
easy-es.global-config.print-dsl=true
easy-es.global-config.db-config.map-underscore-to-camel-case=true
easy-es.global-config.db-config.id-type=customize
easy-es.global-config.db-config.field-strategy=not_empty
easy-es.global-config.db-config.refresh-policy=immediate
easy-es.global-config.db-config.enable-track-total-hits=true
easy-es.dynamic.node1.keep-alive-millis=18000
easy-es.dynamic.node1.address=198.163.192.11:9200
easy-es.dynamic.node1.global-config.i-kun-mode=true
easy-es.dynamic.node1.global-config.process-index-mode=manual
easy-es.dynamic.node1.global-config.async-process-index-blocking=true
easy-es.dynamic.node1.global-config.print-dsl=false
easy-es.dynamic.node1.global-config.db-config.map-underscore-to-camel-case=true
easy-es.dynamic.node1.global-config.db-config.id-type=customize
easy-es.dynamic.node1.global-config.db-config.field-strategy=not_empty
easy-es.dynamic.node1.global-config.db-config.refresh-policy=immediate
easy-es.dynamic.node1.global-config.db-config.enable-track-total-hits=true
easy-es.dynamic.node2.keep-alive-millis=18000
easy-es.dynamic.node2.address=198.163.192.12:9200
easy-es.dynamic.node2.global-config.i-kun-mode=true
easy-es.dynamic.node2.global-config.process-index-mode=manual
easy-es.dynamic.node2.global-config.async-process-index-blocking=true
easy-es.dynamic.node2.global-config.print-dsl=true
easy-es.dynamic.node2.global-config.db-config.map-underscore-to-camel-case=true
easy-es.dynamic.node2.global-config.db-config.id-type=customize
easy-es.dynamic.node2.global-config.db-config.field-strategy=not_empty
easy-es.dynamic.node2.global-config.db-config.refresh-policy=immediate
easy-es.dynamic.node2.global-config.db-config.enable-track-total-hits=true

View File

@ -1,10 +0,0 @@
easy-es.keep-alive-millis=18000
easy-es.global-config.i-kun-mode=true
easy-es.global-config.process-index-mode=manual
easy-es.global-config.async-process-index-blocking=true
easy-es.global-config.print-dsl=true
easy-es.global-config.db-config.map-underscore-to-camel-case=true
easy-es.global-config.db-config.id-type=customize
easy-es.global-config.db-config.field-strategy=not_empty
easy-es.global-config.db-config.refresh-policy=immediate
easy-es.global-config.db-config.enable-track-total-hits=true

View File

@ -1,21 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:easy-es.properties" />
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="indexStrategyFactory" class="org.dromara.easyes.spring.factory.IndexStrategyFactory"/>
<bean id="autoProcessIndexSmoothlyService" class="org.dromara.easyes.spring.index.AutoProcessIndexSmoothlyServiceImpl"/>
<bean id="autoProcessIndexNotSmoothlyService" class="org.dromara.easyes.spring.index.AutoProcessIndexNotSmoothlyServiceImpl"/>
<bean id="easyEsProperties" class="org.dromara.easyes.common.property.EasyEsProperties">
<property name="address" value="192.168.1.123:9200"/>
</bean>
<!-- easy-es配置 -->
<bean id="mapperScannerConfigurer" class="org.dromara.easyes.spring.MapperScannerConfigurer">
<property name="basePackage" value="org.dromara.easyes.test.mapper"/>
<property name="indexStrategyFactory" ref="indexStrategyFactory"/>
<property name="easyEsProperties" ref="easyEsProperties"/>
</bean>
</beans>