一、Nacos注册中心
1、pom.xml配置依赖
<!-- nacos作为注册发现中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2、application.yml配置Nacos服务中心地址
spring:
application:
name: product
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
3、通过@NacosInjected注入Nacos地NamingService
4、使用Nacos提供的OpenAPI方法
(1)注册实例
- registerInstance(serviceName, ip, port)
- registerInstance(serviceName, ip, port, clusterName)
- registerInstance(serviceName, instance)
(2)获取实例
- getAllInstances(serviceName)
- getAllInstances(serviceName, clusters)
(3)监听服务
- subscribe(serviceName, listener)
- subscribe(serviceName, clusters, listener)
【Dubbo】
5、Dubbo使用Nacos实现注册中心
(1)application.properties
dubbo.application.name: spring-boot-dubbo-nacos-sample
dubbo.registry.address=nacos://127.0.0.1:8848
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
(2)通过Dubbo的@Service声明
(3)启动类使用@DubboComponentScan扫描@Service
二、Nacos配置中心
1、pom.xml配置依赖
<!-- nacos作为配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2、bootstrap.properties配置Nacos配置中心地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=6ca49aac-50ec-4e6f-8686-70bb11922fdd
3、使用注解从NacosServer动态读取配置
@NacosPropertySource(dataId = "example", autoRefreshed = true)
@RestController
public class NacosConfigController{
@NacosValue(value = "${info:Local Hello World}", autoRefreshed = true)
private String info;
@GetMapping("/config")
public String get(){
return info;
}
}
(1)@NacosPropertySource:用于加载dataId为example地配置源,autoRefreshed表示开启自动更新;
(2)@NacosValue:设置属性的默认值
4、使用Nacos提供的OpenAPI方法
三、Dubbo
【服务提供者】
1、pom.xml配置依赖
<dependency>
<groupId>com.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
2、application.properties配置Dubbo服务
spring.application.name=spring-dubbo-demo
dubbo.application.name=springboot-provider
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
dubbo.registry.address=N/A
3、声明Dubbo提供的@Service注解发布服务
@Service
public class HelloServiceImpl implements HelloService{
@value("${dubbo.application.name}")
private String servicename;
@Override
public String sayHello(String name){
return servicename;
}
}
4、启动方法上添加@DubboComponentScan,用来扫描Dubbo声明的@Service
@DubboComponentScan
@SpringBootApplication
public class ProviderApplication{
public static void main(Sting[] args){
SpringApplication.run(ProviderApplication.class, args);
}
}
【服务调用者】
1、pom.xml配置依赖
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
2、application.properties配置Dubbo服务
dubbo.application.name=springboot-consumer
3、使用Dubbo提供的@Reference注解获取远程代理服务对象
@Reference(url = "dubbo://192.168.13.1:20880/com.gupaoedu.book.dubbo.helloService")
private HelloService helloService;
【高级配置】
1、集群容错
@Service(cluster = "failfast")
容错模式
(1)Failover Cluster:失败自动切换。调用失败后,切换到集群中其他机器,默认重试两次。
(2)Failfast Cluster:快速失败。调用失败后,立即报错,只发起依次调用。
(3)Failsafe Cluster:失败安全。出现异常时,直接忽略。
(4)Failback Cluster:失败后自动回复。后台记录失败请求,定时重发。
(5)Forking Cluster:并行调用集群中的多个服务,只要其中一个成功就返回。
(6)Broadcast Cluster:广播调用所有的服务提供者,任意一个服务报错则表示服务调用失败。
2、负载均衡
@Service(cluster = "failfast", loadbalance = "roundrobin")
负载均衡策略
(1)Random LoadBalance:随机算法。可能针对性能较好的服务器设置较大的权重值。
(2)RoundRobin LoadBalance:轮询。按照公约后的权重设置轮询比例。
(3)LeastActive LoadBalance:最少活跃调用书。处理较慢的节点将会收到更少的请求。
(4)ConsistentHash LoadBalance:一致性Hash。相同参数的请求总是发送到同一个服务提供者。
3、服务降级
(1)创建降级本地数据默认返回
public class MockHelloService implements HelloService{
@Override
public String sayHello(String s){
return "Sorry, 服务无法访问, 返回降级数据";
}
}
(2)@Reference注解增加Mock参数
@Reference(mock = "com.gupaoedu.book.springcloud.springclouddubboconsumer.MockHelloService", cluster = "failfast")
private HelloService helloService;
4、主机绑定
(1)Dubbo服务对外发布的IP地址,默认顺序
- 查找环境变量中的DUBBO_IP_TO_BIND属性配置的IP地址
- 查找dubbo.protocol.host属性配置的IP地址,默认是空
- 通过LocalHost.getHostAddress获取本机IP地址
- 注册中心的地址,使用Socket通信连接到注册中心的地址后,使用for循环通过socket.getLocalAddress().getHostAddress()扫描各个网卡获取网卡IP地址
(2)服务消费者无法正常调用情况解决办法
- /etc/hosts中配置机器名对应正确的IP地址映射
- 环境变量添加DUBBO_IP_TO_BIND或者DUBBO_IP_TO_REGISTRY属性
- 通过dubbo.protocol.host设置主机地址
无法正常调用原因:Dubbo通过获取本机的hostname映射IP地址,如果IP地址错误,依然会注册ZooKeeper,并且正常启动。
四、Feign
1、pom.xml引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、定义接口,通过@FeignClient注解指定服务名来绑定服务
声明接口的每一个方法都是调用哪个远程服务的哪个请求
@FeignClient("whalemall-coupon")
public interface CouponFeignService {
@PostMapping("/coupon/spubounds/save")
R saveSpuBounds(@RequestBody SpuBoundTo spuBoundTo);
@PostMapping("/coupon/skufullreduction/saveinfo")
R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
}
3、启动类通过@EnableFeignClients注解开启Spring Cloud Feign
@EnableFeignClients(basePackages = "com.island.whalemall.product.feign")
@EnableDiscoveryClient
@MapperScan("com.island.whalemall.product.dao")
@SpringBootApplication
public class WhalemallProductApplication {
public static void main(String[] args) {
SpringApplication.run(WhalemallProductApplication.class, args);
}
}
五、Gateway
1、pom.xml添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、application.yml文件中添加Gateway的路由配置
spring:
cloud:
gateway:
routes:
# 商品服务
- id: product_route
uri: lb://whalemall-product
predicates:
- Path=/api/product/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
六、Seate
七、OSS
1、pom.xml添加依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
2、使用OSS域名新建OSSClient
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 关闭OSSClient。
ossClient.shutdown();
3、创建examplebucket存储空间
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
OSS ossClient = null;
try {
// 创建OSSClient实例。
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 创建存储空间。
ossClient.createBucket(bucketName);
} catch (OSSException e){
e.printStackTrace();
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}
4、通过流式上传方式上传文件到OSS
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写文件名。文件名包含路径,不包含Bucket名称。例如exampledir/exampleobject.txt。
String objectName = "exampledir/exampleobject.txt";
OSS ossClient = null;
try {
// 创建OSSClient实例。
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String content = "Hello OSS";
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
} catch (OSSException e){
e.printStackTrace();
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}
5、通过流式下载方式从OSS下载文件
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写文件名。文件名包含路径,不包含Bucket名称。例如exampledir/exampleobject.txt。
String objectName = "exampledir/exampleobject.txt";
OSS ossClient = null;
try {
// 创建OSSClient实例。
ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 调用ossClient.getObject返回一个OSSObject实例,该实例包含文件内容及文件元信息。
OSSObject ossObject = ossClient.getObject(bucketName, objectName);
// 调用ossObject.getObjectContent获取文件输入流,可读取此输入流获取其内容。
InputStream content = ossObject.getObjectContent();
if (content != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
while (true) {
String line = reader.readLine();
if (line == null) break;
System.out.println("\n" + line);
}
// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
content.close();
}
} catch (OSSException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}
八、RabbitMQ
1、pom.xml引入amqp依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、applications.properties配置RabbitMQ服务
# RabbitMQ 配置
# RabbitMQ 服务器地址
spring.rabbitmq.host = localhost
# RabbitMQ 端口
spring.rabbitmq.post = 5672
# RabbitMQ 用户
spring.rabbitmq.username = admin
# RabbitMQ 密码
spring.rabbitmq.password = 123456
# 是否确认发送的消息已经被消费
spring.rabbitmq.publisher-confirms = true
#RabbitMQ 的消息队列名称,由它发送字符串
rabbitmq.queue.msg = spring-boot-queue-msg
#RabbitMQ 的消息队列名称,由它发送用户对象
rabbitmq.queue.user = spring-boot-queue-user
3、主启动类使用@EnableRabbit开启功能
4、使用RabbitMQ
(1)使用管理组件AmqpAdmin创建Exchange、Queue、Binding
//1、自动注入
@Autowire
AdqpAdmin amqpAdmin;
//2、创建交换机
DirectExchange directExchange = new DirectExchange($name,$type,$autodelete,$Arg参数);
//3、管理组件声明交换机
amqpAdmin.declareExchange(directExchange);
//4、创建队列
Queue queue = new queue($name,$type,$exclusive,$autodelete,$Arg参数);
//5、管理组件声明队列
amqpAdmin.declareQueue(queue)
//6、创建绑定关系
Binding binding = new Binding($distination,$distinationtype【Distination.Type.Queue or Distination.Type.Exchange】,$exchange,$routingKey,$Arg参数(可null));
//7、管理器声明绑定关系
amqpAdmin.declareBinding(binding);
(2)使用RabbitTemplate收发消息
//1、自动注入
@Autowire
RabbitTemplate rabbitTemplate;
//2、发送消息(如果发送消息是对象,会使用序列化机制,所以对象必须实现Serializable)
rabbitTemplate.convertAndSend($exchange,$routingKey,$object【消息】);
//3、发送对象类型的消息可以是JSON
需要配置自己的RabbitConfig.java
给容器中放置消息转换器
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter;
}
5、监听RabbitMQ消息
(1)使用@RabbitListener(queues = {"xxx","xxx",…})(必须开启了@EnableRabbit)(可以标注在类或者方法上)
//1、获取消息体(入参Message message,T<发送消息的类型>OrderReturnReasonEntity content,当前传输数据的通道Channel channel)
byte[] body = message.getBody();
JSON.perse();
//2、获取消息头属性信息
MessageProperties = message.getMessageProperties();
//3、Queue中一个消息只能被一个客户端接收,且消息是被有序接收,只有一个消息被处理完才会处理下一个消息
(2)使用@RabbitHandler(可以标注在方法上)(可以重载接收同一队列不同类型消息)
6、Rabbit消息确认机制
(1)【发送端】ConfirmCallback服务收到收到信息回调
1)开启发送端确认配置application.properties
spring.rabbitmq.publisher-confirms=true
2)定制rabbitTemplate,设置确认回调
@Autowired
RedisTemplate redisTemplate;
//SpringBoot生成config对象后与执行这个方法
@PostConstruct
public void initRabbitTemplate(){
//设置回调
redisTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
@override
public void confirm(CorrelationData correlationData【唯一Id】, boolean ack【确认】, String cause【原因】){
}
});
}
(2)【发送端】ReturnCallback消息正确抵达队列进行回调
1)开启发送端抵达消息队列确认配置application.properties
spring.rabbitmq.publisher-returns=true
# 抵达队列后优先异步执行returns回调确认
spring.rabbitmq.template-mandatory=true
2)定制rabbitTemplate,没有触发投递队列时,进行回调
@Autowired
RedisTemplate redisTemplate;
//SpringBoot生成config对象后与执行这个方法
@PostConstruct
public void initRabbitTemplate(){
//设置回调
redisTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
@override
public void returnMessage(Message message【投递失败的消息详细信息】, int replayCode【恢复状态码】, String relayText【回复的文本内容】,String exchange【处理的交换机】,String routingKey【消息的路由键】){
}
});
}
(3)消费端确认
第一种方式:默认自动确认的,只要消息接收到,服务端就会移除这个消息
存在问题:收到很多消息消息时,只有一个消息被成功处理,中途宕机,依然确认全部收到删除了队列中数据,造成消息丢失。
第二种方式:手动确认
1)开启手动确认消息配置application.properties
spring.rabbitmq.listener.simple.acknowledge.-mode=manual
2)确认签收
long deliveryTag = message.getMessageProperties().getDeliveryTag();
channel.basicAck(deliveryTag, false【不开启批量签收】);
3)拒收
channel.basicNAck(deliveryTag, false【不开启批量拒收】,true【重新入队】);
九、Sentinel
1、pom.xml引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
2、通过@SentinelResource配置资源保护规则
@RestController
public class HelloController{
@SentinelResource(value = "hello", blockHandler = "blockHandlerHello")
@GetMapping("/say")
public String hello(){
return "Hello World";
}
//限流保护Controller资源
public String blockHandlerHello(BlockException e){
return "被限流了";
}
}
3、手动配置规则
//可以配置流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则、热点参数规则
public class FlowRuleInitFunc implements InitFunc{
@Override
public void init() throws Exception{
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
//限流阈值
rule.setCount(1);
//设置需要保护的资源
rule.setResource("hello");
//流控规则
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//针对调用来源限流
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
【限流】
限流的主要目的是通过,限制并发访问 或者 限制一个时间窗口 内允许处理的请求数量,来保护系统,一旦达到限制数量则对当前请求进行处理采取对应的拒绝策略。
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("doSomething");
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rule.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
rule.setClusterMode(fasle);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
- resource:设置需要保护的资源。
- count:限流阈值。
- Grade:限流阈值类型,QPS模式(1)或并发线程数模式(0)。
- limitApp:是否需要针对调用来源进行限流,默认是default,即不区分调用来源。
- strategy:调用关系限流策略——直接、链路、关联。
- controlBehavior:流控行为,包括直接拒绝、排队等待、慢启动模式,默认是直接拒绝。
- clusterMode:是否是集群限流,默认为否。
【熔断】
熔断是指当前服务提供者无法正常为服务调用者提供服务时,比如请求超时、服务异常等,为了防止整个系统出现雪崩效应,暂时将出现故障的接口隔离出来,断绝与外部接口的联系,当触发熔断之后,后续一段时间内该服务调用者的请求都会直接失败,知道目标服务恢复正常。
private static void initDegradeRule(){
List<DegradeRule> rules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("KEY");
degradeRule.setCount(10);
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setTimeWindow(10);
degradeRule.setMinRequestAmount(5);
degradeRule.setRtSlowRequestAmount(5);
rules.add(degradeRule);
}
- grade:熔断策略。支持秒级RT(RuleConstant.DEGRADE_GRADE_RT)、秒级异常比例(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)、分钟级异常数(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)。
- timeWindow:熔断降级的时间窗口,单位s。
- rtSlowRequestAmount:在RT模式下,1s内持续多少个请求的平均RT超出阈值后触发熔断,默认值是5。
- minRequestAmount:触发的异常熔断最小请求数,请求数小于该值时即使异常比例超出阈值也不会触发熔断,默认值是5。
3、基于Sentinel Dashboard配置规则
(1)启动Sentinel Dashboard
(2)在application.yml
spring:
application:
name: spring-cloud-sentinel-sample
cloud:
sentinel:
transport:
dashboard: 192.168.216.128:7777
(3)REST接口
@RestController
public class DashboardController{
@GetMapping("/dash")
public String dash(){
return "Hello Dash";
}
}
4、自定义URL限流异常
@Service
public class CustomUrlBlockHandler implements UrlBlockHandler{
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
httpServletResponse.setHeader("Content-Type", "application/json;charset=UTF-8");
String message = "{\"code\":999,\"msg\":\"访问人数过多\"}";
httpServletResponse.getWriter().write(message);
}
}
降级页面
spring.cloud.sentinel.servlet.block-page={url}
5、通过UrlCleaner接口实现URL资源清洗
@RestController
public class UrlCleanController{
@GetMapping("/clean/{id}")
public String clean(@PathVariable("id")int id){
return "Hello,Cleaner";
}
}
@Service
public class CustomerUrlCleaner implements UrlCleaner{
@Override
public String clean(String originUrl){
if(StringUtils.isEmpty(originUrl)){
return originUrl;
}
if(originUrl.startsWith("/clean/")){
return "/clean/*";
}
return originUrl;
}
}
6、集成Nacos实现动态规则同步
7、Dubbo集成Sentinel
(1)pom.xml添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>1.7.1</version>
</dependency>
(2)Sentinel Apache Dubbo Adapter自定义开启关闭过滤器
(3)Dubbo服务接入Sentinel Dashboard
1)引入sentinel-transport-simple-http依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.7.1</version>
</dependency>
2)添加启动参数
-Djava.net.preferIPv4Stack=true
-Dcsp.sentinel.api.port=8720
-Dcsp.sentinel.dashboard.server=192.168.216.128:7777
-Dproject.name=spring-cloud.sentinel-dubbo.provider
3)登录Sentinel Dashboard进行簇点链路操作
(4)Dubbo服务限流规则持久化
1)添加sentinel-datasource-nacos
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.7.1</version>
</dependency>
2)通过Sentinel提供的InitFunc扩展点,实现Nacos数据源配置
public class NacosDataSourceInitFunc implements InitFunc{
private String serverAddr="192.168.216.128:8848";
private String groupId="DEFAULT_GROUP";
private String dataId="spring-cloud.sentinel-dubbo.provider-sentinel-flow";
@Override
public void init() throws Exception {
loadNacosData();
}
private void loadNacosData(){
ReadableDataSource<String,List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(serverAddr, groupId, dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>(){
}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}
3)访问Sentinel Dashboard
十、ElasticSearch
Java操作ElasticSearch有两种方式,一个是通过ES的9300端口使用TCP的方式操作,另一种是通过ES的9200端口使用HTTP的方式
1)9300 TCP
spring-data-elasticsearch:transport-api.jar
-
springboot 版本不同, transport-api.jar 不同,不能适配 es 版本
-
7.x 已经不建议使用,8 以后就要废弃
2)9200 HTTP
-
JestClient:非官方,更新慢
-
RestTemplate:模拟发 HTTP 请求,ES 很多操作需要自己封装,麻烦
-
HttpClient:同上
-
Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,API 层次分明,上手简单
综上所述,选择Elasticsearch-Rest-Client(elasticsearch-rest-high-level-client)是最优的选择,下面记录如何整合
1、pom.xml引入依赖
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.3.2</version>
</dependency>
<!-- Java High Level REST Client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.3.2</version>
</dependency>
2、application.yml配置
elasticsearch:
ip: localhost:9200
3、配置ElasticsearchRestClients
@Configuration
public class ElasticsearchRestClient {
/**
* ES地址,ip:port
*/
@Value("${elasticsearch.ip}")
String ipPort;
@Bean
public RestClientBuilder restClientBuilder() {
return RestClient.builder(makeHttpHost(ipPort));
}
@Bean(name = "highLevelClient")
public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
restClientBuilder.setMaxRetryTimeoutMillis(60000);
return new RestHighLevelClient(restClientBuilder);
}
private HttpHost makeHttpHost(String s) {
String[] address = s.split(":");
String ip = address[0];
int port = Integer.parseInt(address[1]);
return new HttpHost(ip, port, "http");
}
}
4、添加
localhost:9200/customer/_doc/1?pretty
{
"city": "北京",
"useragent": "Mobile Safari",
"sys_version": "Linux armv8l",
"province": "北京",
"event_id": "",
"log_time": 1559191912,
"session": "343730"
}
5、条件查询
@Service
public class TestService {
@Autowired
RestHighLevelClient highLevelClient;
private void search(RestHighLevelClient highLevelClient) throws IOException {
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("customer");
searchRequest.types("_doc");
// 条件=
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("city", "北京");
TermQueryBuilder termQuery = QueryBuilders.termQuery("province", "福建");
// 范围查询
RangeQueryBuilder timeFilter = QueryBuilders.rangeQuery("log_time").gt(12345).lt(343750);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
QueryBuilder totalFilter = QueryBuilders.boolQuery()
.filter(matchQuery)
.filter(timeFilter)
.mustNot(termQuery);
int size = 200;
int from = 0;
long total = 0;
do {
try {
sourceBuilder.query(totalFilter).from(from).size(size);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchRequest.source(sourceBuilder);
SearchResponse response = highLevelClient.search(searchRequest);
SearchHit[] hits = response.getHits().getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
total = response.getHits().totalHits;
System.out.println("测试:[" + total + "][" + from + "-" + (from + hits.length) + ")");
from += hits.length;
// from + size must be less than or equal to: [10000]
if (from >= 10000) {
System.out.println("测试:超过10000条直接中断");
break;
}
} catch (Exception e) {
e.printStackTrace();
}
} while (from < total);
}
}
十一、MySQL
1、pom.xml引入MySQL依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
2、application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/spring_boot_chapter5
spring.datasource.username=root
spring.datasource.password=123456
# 即使注释掉了驱动,SpringBoot会尽可能判断数据源,然后默认匹配
# spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 指定数据库连接池类型
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
# 最大等待连接中的数量,设 0 为没有限制
spring.datasource.dbcp2.max-idle=10
# 最大连接活动数
spring.datasource.dbcp2.max-total=50
# 最大等待毫秒数,单位ms
spring.datasource.dbcp2.max-wait-millis=10000
# 数据库连接池初始化连接数
spring.datasource.dbcp2.initial-size=5
3、使用MyBatis框架
(1)pom.xml引入依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
(2)application.properties
# MyBatis映射文件通配
mybatis.mapper-locations=classpath:com/springboot/chapter/mapper/*.xml
# Mybatis扫描别名包,和注解@Alias联用
mybatis.type-aliases-package=com.springboot.chapter.pojo
# 配置typeHandler的扫描包
mybatis.type-handlers-package=com.springboot.chapter.typehandler
可配置属性
- properties :属性
- settings:设置
- typeAliases:类型别名
- typeHandlers:类型处理器
- objectFactory:对象工厂
- plugins:插件
- environments:数据库环境
- databaseIdProvider:数据库厂商标识
- mappers:映射器
(3)使用@Mapper注解表示Mapper(Dao)接口
(4)启动类使用@MapperScan()扫描
十二、Redis
1、pom.xml引入Redis依赖
<!-- 引入Redis的客户端驱动 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
2、application.properties
# 配置连接池属性
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-wait=2000
# 配置Redis服务器属性
spring.redis.port=6379
spring.redis.host=192.168.11.131
spring.redis.password=123456
# Redis连接超时时间,单位ms
spring.redis.timeout=1000
3、使用springboot提供的StringRedisTemplate来操作redis(是对jedis的再次封装)
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
//保存
ops.set("hello", "world_" + UUID.randomUUID().toString());
//查询
String hello = ops.get("hello");