环境介绍:java的jdk为1.8,springboot版本为2.1.4.RELEASE,elasticsearch在centos上装的为6.2.2,redis为2.9.3版本。
相信很多人在整合这个的时候都遇到一个问题:
nested exception is java.lang.IllegalStateException:
availableProcessors is already set to [8], rejecting [8]
可能不同的人后面的数字可能不同,网上大多数给出的方案是添加这个:
System.setProperty("es.set.netty.runtime.available.processors", "false")
public static void main(String[] args) {
System.setProperty("es.set.netty.runtime.available.processors", "false");
SpringApplication.run(EsApplication.class, args);
}
可能启动不报错了,但是你去运行elasticsearch相关的api时就会出错,然后依然会报如下的错误提示:
Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'requestMappingHandlerAdapter' defined in class path resource
[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcC
onfiguration.class]: Bean instantiation via factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to instantiate
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter]:
Factory method 'requestMappingHandlerAdapter' threw exception; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'mvcConversionService' defined in class path resource
[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcC
onfiguration.class]: Bean instantiation via factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to instantiate
[org.springframework.format.support.FormattingConversionService]: Factory method
'mvcConversionService' threw exception; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'bookRepository': Cannot resolve reference to bean 'elasticsearchTemplate' while setting
bean property 'elasticsearchOperations'; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean
with name 'elasticsearchTemplate' defined in class path resource
[org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfigura
tion.class]: Unsatisfied dependency expressed through method 'elasticsearchTemplate'
parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'elasticsearchClient' defined in class path resource
[org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration
.class]: Bean instantiation via factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to instantiate
[org.elasticsearch.client.transport.TransportClient]: Factory method
'elasticsearchClient' threw exception; nested exception is
java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8]
大致的问题差不多就是redis和es一起时候netty相关设置初始化数的问题,看springboot源码时候知道spring的autoconfigeration系列自动配置是有个先后顺序的,当你在配置文件中打开debug = true 的时候就能看到相应的自动配置启动顺序。
要想解决这个问题,我们就可以让elasticsearch的自动配置类启动在redis前面,这样这个问题就不会出现了,也无需配置System.setProperty("es.set.netty.runtime.available.processors", "false")。
我们直接写两个配置类一个是redis的,一个是elasticsearch的。如下:
第一个是RedisConfig:
package com.elastic.es.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
@Configuration
public class RedisConfig {
//重写RedisAutoConfiguration
@Bean
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer ser = new Jackson2JsonRedisSerializer(Object.class);
template.setDefaultSerializer(ser);
return template;
}
//配置redis缓存管理器,将序列化机制设置为json格式
@Primary //设置为默认缓存管理器
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1)); // 设置缓存有效期一小时
Jackson2JsonRedisSerializer ser = new Jackson2JsonRedisSerializer(Object.class);
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(ser));
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
}
第二个是ElasticConfig :
package com.elastic.es.config;
import org.elasticsearch.client.Client;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
@Configuration
@AutoConfigureBefore(RedisConfig.class)
public class ElasticConfig {
@Bean
public ElasticsearchTemplate elasticsearchTemplate(Client client,
ElasticsearchConverter converter) {
try {
return new ElasticsearchTemplate(client, converter);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
@Bean
public ElasticsearchConverter elasticsearchConverter(
SimpleElasticsearchMappingContext mappingContext) {
return new MappingElasticsearchConverter(mappingContext);
}
@Bean
public SimpleElasticsearchMappingContext mappingContext() {
return new SimpleElasticsearchMappingContext();
}
}
我们给ElasticConfig上加了一个@AutoConfigureBefore(RedisConfig.class)配置类,里面的参数配置的是上面的redis的配置类,当然如果你自己不重写redis的配置类你可以加@AutoConfigureBefore(RedisAutoConfiguration.class),这个注解就是告诉springboot自动装配的时候将ElasticConfig配置类在redis的自动装配配置类之前生效,这样就不会再出现上面的问题了,启动不会报错,调用api亦不会出错。
如果有疑问,可以留言告诉我。
整合的项目地址:https://github.com/satanGod/es.git