今日重点
一、nacos配置中心
在弹出的表单中,填写配置信息:
项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。
二、配置中心的使用步骤
1)引入nacos-config依赖
首先,在user-service服务中,引入nacos-config的客户端依赖:
<!--nacos配置管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
2)添加bootstrap.yaml
然后,在user-service中添加一个bootstrap.yaml文件,内容如下:
spring: application: name: userservice # 服务名称 cloud: #nacos注册中心配置内容 nacos: discovery: server-addr: 192.168.94.129:8848 cluster-name: HZ #开发环境的区别 namespace: 73be46a4-c53c-4b10-a68f-205698afef0e #区分统一环境下的不同项目组 group: cloud_project config: server-addr: 192.168.94.129:8848 cluster-name: HZ namespace: 73be46a4-c53c-4b10-a68f-205698afef0e group: cloud_project file-extension: yml #修改日志级别,可以显示出读取的配置信息 logging: level: cn.itcast: debug com: alibaba: cloud: nacos: client: debug
3)读取nacos配置
在user-service中的UserController中添加业务逻辑,读取pattern.dateformat配置:
三、热更新
要实现配置热更新,可以使用两种方式:
1.2.1.方式一
在@Value注入的变量所在类上添加注解@RefreshScope:
1.2.2.方式二
使用@ConfigurationProperties注解代替@Value注解。
在user-service服务中,添加一个类,读取patterrn.dateformat属性:
package cn.itcast.user.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @Data @ConfigurationProperties(prefix = "pattern") public class PatternProperties { private String dateformat; }
在UserController中使用这个类代替@Value:
完整代码:
package cn.itcast.user.web; import cn.itcast.user.config.PatternProperties; import cn.itcast.user.pojo.User; import cn.itcast.user.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @Slf4j @RestController @RequestMapping("/user") // @RefreshScope public class UserController { @Autowired private UserService userService; //@Value("${pattern.dateformat}") //private String dateformat; @Autowired private PatternProperties properties; /** * 获取当前系统时间,并进行格式化 * @return */ // @GetMapping("now") // public String now(){ // System.out.println("日志参数的格式为: "+dateformat); // return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat)); // } @GetMapping("now") public String now(){ System.out.println("日志参数的格式为: "+properties.toString()); return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat())); } @GetMapping("prop") public PatternProperties prop(){ return properties; } /** * 路径: /user/110 * * @param id 用户id * @return 用户 */ @GetMapping("/{id}") public User queryById(@PathVariable("id") Long id) { return userService.queryById(id); } }
四、多环境支持
项目开发过程中,可能会存在多种环境,并且每一种环境所设置的配置都是不同的。nacos可以同时支持多环境配置,可以满足生产环境下的需求。
不同的开发环境:namespace 区分
不同的开发组:group 区分
不同的项目: dataid 区分
不同种类的配置:profile
五、共享配置
1)在nacos中添加 datasource-config.yml
如下图:
配置信息:
spring: datasource: url: jdbc:mysql://192.168.94.129:3306/xxxxx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false username: root password: itcast142 driver-class-name: com.mysql.jdbc.Driver
2)在user-service和order-service的bootstrap.yml文件中添加内容
spring: cloud: nacos: config: shared-configs: - dataId: db-config.yml
六、配置持久化
1)mysql中新建nacos_config数据库,并执行资料/nacos持久化下的nacos-mysql.sql
参考github:nacos/nacos-mysql.sql at master · alibaba/nacos · GitHub
如果github上不去,可以直接在今天的资料里nacos_config.sql文件直接导入到自己的数据库中。
2)进入nacos容器
docker exec -it nacos /bin/bash
3)修改conf目录下application.properties
spring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://自己的ip:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true db.user=root db.password=自己的密码
记得将文件中的原有配置注释掉,要不然会和上面新增配置内容冲突,可以查考今天下发资料中的application.properties 文件。
4)重启nacos容器
docker restart nacos #查看nacos的日志 docker logs -f nacos
访问nacos可以发现,配置中心中没有了配置内容,因为nacos已经连接了mysql,mysql中并没有配置文件
七、远程调用Feign
先来看我们以前利用RestTemplate发起远程调用的代码:
存在下面的问题:
•代码可读性差,编程体验不统一
•参数复杂URL难以维护
Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign
其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。
Feign: 代替消费者向提供者发送请求,并接受返回结果
openfeign: SpringCloud官方提供的组件
八、使用步骤
使用Feign的步骤:
① 引入依赖
② 添加@EnableFeignClients注解
③ 编写FeignClient接口
④ 使用FeignClient中定义的方法代替RestTemplate
九、日志级别配置
也可以基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level的对象:
public class DefaultFeignConfiguration { @Bean public Logger.Level feignLogLevel(){ return Logger.Level.BASIC; // 日志级别为BASIC } }
如果要全局生效,将其放到启动类的@EnableFeignClients这个注解中:
package cn.itcast.order; import cn.itcast.order.config.DefaultFeignConfiguration; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @MapperScan("cn.itcast.order.mapper") @SpringBootApplication // 配置类的方式开启全局日志记录 @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class) // 开启feign客户端的支持 @EnableFeignClients // 开启feign客户端的支持 public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } //...... }
如果是局部生效,则把它放到对应的@FeignClient这个注解中:
package cn.itcast.order.feign; import cn.itcast.order.config.DefaultFeignConfiguration; import cn.itcast.order.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; // 指定服务日志配置 @FeignClient(value = "userservice",configuration = DefaultFeignConfiguration.class) public interface UserFeignClient { @GetMapping("/user/{id}") User queryById(@PathVariable("id") Long id); }
十、优化调用性能
总结,Feign的优化:
-
日志级别尽量用basic
2.使用HttpClient或OKHttp代替URLConnection
① 引入feign-httpClient依赖
② 配置文件开启httpClient功能,设置连接池参数
十一、最佳实践
所谓最近实践,就是使用过程中总结的经验,最好的一种使用方式。
自习观察可以发现,Feign的客户端与服务提供者的controller代码非常相似:
十二、网关
1)创建gateway服务,引入依赖
创建服务:
引入依赖:
<!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--nacos服务发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
2)编写启动类
package cn.itcast.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
3)编写基础配置和路由规则
创建application.yml文件,内容如下:
server: port: 10010 # 网关端口 spring: application: name: gateway # 服务名称 cloud: nacos: server-addr: localhost:8848 # nacos地址 gateway: routes: # 网关路由配置 - id: user-service # 路由id,自定义,只要唯一即可 # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址 uri: lb://userservice # 路由的目标地址 lb就是负载均衡,后面跟服务名称 predicates: # 路由断言,也就是判断请求是否符合路由规则的条件 - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
我们将符合Path
规则的一切请求,都代理到 uri
参数指定的地址。
本例中,我们将 /user/**
开头的请求,代理到lb://userservice
,lb是负载均衡,根据服务名拉取服务列表,实现负载均衡。
4)重启测试
5重启网关,访问http://localhost:10010/user/1时,符合/user/**
规则,请求转发到uri:http://userservice/user/1,得到了结果:
)
十三、核心功能
十四、断言工厂使用
我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
例如Path=/user/**是按照路径匹配,这个规则是由
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory
类来
处理的,像这样的断言工厂在SpringCloudGateway还有十几个:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=.somehost.org,.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
Weight | 权重处理 |
我们只需要掌握Path这种路由工程就可以了。
十五、过滤器的使用
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现。
定义方式是实现GlobalFilter接口。
十六、跨域问题和解决方案
协议,域名,端口三者中任意一者不同即为跨域
跨域:域名不一致就是跨域,主要包括:
-
域名不同: www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
-
域名相同,端口不同:localhost:8080和localhost8081
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方案:CORS,这个以前应该学习过,这里不再赘述了。不知道的 可查看跨域资源共享 CORS 详解 - 阮一峰的网络日志