当前位置: 首页 > news >正文

作风建设简报--门户网站网站建设人员工作职责

作风建设简报--门户网站,网站建设人员工作职责,做阿里巴巴网站卖货咋样,wordpress增加4041.1 微服务的架构特征#xff1a; 单一职责#xff1a;微服务拆分粒度更小#xff0c;每一个服务都对应唯一的业务能力#xff0c;做到单一职责 自治#xff1a;团队独立、技术独立、数据独立#xff0c;独立部署和交付 面向服务#xff1a;服务提供统一标准的接口 单一职责微服务拆分粒度更小每一个服务都对应唯一的业务能力做到单一职责 自治团队独立、技术独立、数据独立独立部署和交付 面向服务服务提供统一标准的接口与语言和技术无关 隔离性强服务调用做好隔离、容错、降级避免出现级联问题 微服务的上述特性其实是在给分布式架构制定一个标准进一步降低服务之间的耦合度提供服务的独立性和灵活性。做到高内聚低耦合。 因此可以认为微服务是一种经过良好架构设计的分布式架构方案 。 但方案该怎么落地选用什么样的技术栈全球的互联网公司都在积极尝试自己的微服务落地方案。 其中在Java领域最引人注目的就是SpringCloud提供的方案了。 1.2.SpringCloud SpringCloud是目前国内使用最广泛的微服务框架。官网地址https://spring.io/projects/spring-cloud。 SpringCloud集成了各种微服务功能组件并基于SpringBoot实现了这些组件的自动装配从而提供了良好的开箱即用体验。 其中常见的组件包括 *另外SpringCloud底层是依赖于SpringBoot的并且有版本的兼容关系如下 笔记采用的SpringBoot版本是2.3.x版本。 1.3.总结 单体架构简单方便高度耦合扩展性差适合小型项目。例如学生管理系统 分布式架构松耦合扩展性好但架构复杂难度大。适合大型互联网项目例如京东、淘宝 微服务一种良好的分布式架构方案 ①优点拆分粒度更小、服务更独立、耦合度更低 ②缺点架构非常复杂运维、监控、部署难度提高 SpringCloud是微服务架构的一站式解决方案集成了各种优秀微服务功能组件 2.服务拆分和远程调用 任何分布式架构都离不开服务的拆分微服务也是一样。   2.1.服务拆分原则 不同微服务不要重复开发相同业务 微服务数据独立不要访问其它微服务的数据库 微服务可以将自己的业务暴露为接口供其它微服务调用 2.2.服务拆分示例 以资料中的微服务cloud-demo为例其结构如下 cloud-demo父工程管理依赖 order-service订单微服务负责订单相关业务 user-service用户微服务负责用户相关业务 要求 订单微服务和用户微服务都必须有各自的数据库相互独立 订单服务和用户服务都对外暴露Restful的接口 订单服务如果需要查询用户信息只能调用用户服务的Restful接口不能查询用户数据库 2.2.1.导入Sql语句 首先将资料提供的cloud-order.sql和cloud-user.sql导入到mysql中 cloud-user表中初始数据如下 cloud-order表中初始数据如下 cloud-order表中持有cloud-user表中的id字段。 2.2.2.导入demo工程 用IDEA导入资料提供的Demo 项目结构如下 导入后会在IDEA右下角出现弹窗 点击弹窗然后按下图选择 会出现这样的菜单 配置下项目使用的JDK 2.3.实现远程调用案例 在order-service服务中有一个根据id查询订单的接口 根据id查询订单返回值是Order对象如图 其中的user为null 在user-service中有一个根据id查询用户的接口 查询的结果如图 2.3.1.案例需求 修改order-service中的根据id查询订单业务要求在查询订单的同时根据订单中包含的userId查询出用户信息一起返回。 因此我们需要在order-service中 向user-service发起一个http的请求调用http://localhost:8081/user/{userId}这个接口。 大概的步骤是这样的 注册一个RestTemplate的实例到Spring容器 修改order-service服务中的OrderService类中的queryOrderById方法根据Order对象中的userId查询User 将查询的User填充到Order对象一起返回 2.3.2.注册RestTemplate 首先我们在order-service服务中的OrderApplication启动类中注册RestTemplate实例 package cn.itcast.order;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate;MapperScan(cn.itcast.order.mapper) SpringBootApplication public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}Beanpublic RestTemplate restTemplate() {return new RestTemplate();} } 2.3.3.实现远程调用 修改order-service服务中的cn.itcast.order.service包下的OrderService类中的queryOrderById方法 2.4.提供者与消费者 在服务调用关系中会有两个不同的角色 服务提供者一次业务中被其它微服务调用的服务。提供接口给其它微服务 服务消费者一次业务中调用其它微服务的服务。调用其它微服务提供的接口 但是服务提供者与服务消费者的角色并不是绝对的而是相对于业务而言。 如果服务A调用了服务B而服务B又调用了服务C服务B的角色是什么 对于A调用B的业务而言A是服务消费者B是服务提供者 对于B调用C的业务而言B是服务消费者C是服务提供者 因此服务B既可以是服务提供者也可以是服务消费者。 3.Eureka注册中心 假如我们的服务提供者user-service部署了多个实例如图 大家思考几个问题 order-service在发起远程调用的时候该如何得知user-service实例的ip地址和端口 有多个user-service实例地址order-service调用时该如何选择 order-service如何得知某个user-service实例是否依然健康是不是已经宕机 3.1.Eureka的结构和作用 这些问题都需要利用SpringCloud中的注册中心来解决其中最广为人知的注册中心就是Eureka其结构如下   回答之前的各个问题。 问题1order-service如何得知user-service实例地址 获取地址信息的流程如下 user-service服务实例启动后将自己的信息注册到eureka-serverEureka服务端。这个叫服务注册 eureka-server保存服务名称到服务实例地址列表的映射关系 order-service根据服务名称拉取实例地址列表。这个叫服务发现或服务拉取 问题2order-service如何从多个user-service实例中选择具体的实例 order-service从实例列表中利用负载均衡算法选中一个实例地址 向该实例地址发起远程调用 问题3order-service如何得知某个user-service实例是否依然健康是不是已经宕机 user-service会每隔一段时间默认30秒向eureka-server发起请求报告自己状态称为心跳 当超过一定时间没有发送心跳时eureka-server会认为微服务实例故障将该实例从服务列表中剔除 order-service拉取服务时就能将故障实例排除了 因此接下来我们动手实践的步骤包括 3.2.搭建eureka-server 首先大家注册中心服务端eureka-server这必须是一个独立的微服务 3.2.1.创建eureka-server服务 在cloud-demo父工程下创建一个子模块 填写模块信息 然后填写服务信息 3.2.2.引入eureka依赖 引入SpringCloud为eureka提供的starter依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-server/artifactId /dependency 3.2.3.编写启动类 给eureka-server服务编写一个启动类一定要添加一个EnableEurekaServer注解开启eureka的注册中心功能 package cn.itcast.eureka;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;SpringBootApplication EnableEurekaServer public class EurekaApplication {public static void main(String[] args) {SpringApplication.run(EurekaApplication.class, args);} } 3.2.4.编写配置文件 编写一个application.yml文件内容如下 server:port: 10086 spring:application:name: eureka-server eureka:client:service-url: defaultZone: http://127.0.0.1:10086/eureka 3.2.5.启动服务 启动微服务然后在浏览器访问http://127.0.0.1:10086 看到下面结果应该是成功了 3.3.服务注册 下面我们将user-service注册到eureka-server中去。 1引入依赖 在user-service的pom文件中引入下面的eureka-client依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId /dependency 2配置文件 在user-service中修改application.yml文件添加服务名称、eureka地址 spring:application:name: userservice eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka 3启动多个user-service实例 为了演示一个服务有多个实例的场景我们添加一个SpringBoot的启动配置再启动一个user-service。 首先复制原来的user-service启动配置 然后在弹出的窗口中填写信息 现在SpringBoot窗口会出现两个user-service启动配置 不过第一个是8081端口第二个是8082端口。 启动两个user-service实例 查看eureka-server管理页面 3.4.服务发现 下面我们将order-service的逻辑修改向eureka-server拉取user-service的信息实现服务发现。 1引入依赖 之前说过服务发现、服务注册统一都封装在eureka-client依赖因此这一步与服务注册时一致。 在order-service的pom文件中引入下面的eureka-client依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId /dependency2配置文件 服务发现也需要知道eureka地址因此第二步与服务注册一致都是配置eureka信息 在order-service中修改application.yml文件添加服务名称、eureka地址 spring:application:name: orderservice eureka:client:service-url:defaultZone: http://127.0.0.1:10086/eureka 3服务拉取和负载均衡 最后我们要去eureka-server中拉取user-service服务的实例列表并且实现负载均衡。 不过这些动作不用我们去做只需要添加一些注解即可。 在order-service的OrderApplication中给RestTemplate这个Bean添加一个LoadBalanced注解 修改order-service服务中的cn.itcast.order.service包下的OrderService类中的queryOrderById方法。修改访问的url路径用服务名代替ip、端口 spring会自动帮助我们从eureka-server端根据userservice这个服务名称获取实例列表而后完成负载均衡。 4.Ribbon负载均衡 上一节中我们添加了LoadBalanced注解即可实现负载均衡功能这是什么原理呢 4.1.负载均衡原理 SpringCloud底层其实是利用了一个名为Ribbon的组件来实现负载均衡功能的。 那么我们发出的请求明明是http://userservice/user/1怎么变成了http://localhost:8081的呢 4.2.源码跟踪 为什么我们只输入了service名称就可以访问了呢之前还要获取ip和端口。 显然有人帮我们根据service名称获取到了服务实例的ip和端口。它就是LoadBalancerInterceptor这个类会在对RestTemplate的请求进行拦截然后从Eureka根据服务id获取服务列表随后利用负载均衡算法得到真实的服务地址信息替换服务id。 我们进行源码跟踪 1LoadBalancerIntercepor 可以看到这里的intercept方法拦截了用户的HttpRequest请求然后做了几件事 request.getURI()获取请求uri本例中就是 http://user-service/user/8 originalUri.getHost()获取uri路径的主机名其实就是服务iduser-service this.loadBalancer.execute()处理服务id和用户请求。 这里的this.loadBalancer是LoadBalancerClient类型我们继续跟入。 2LoadBalancerClient 继续跟入execute方法 代码是这样的 getLoadBalancer(serviceId)根据服务id获取ILoadBalancer而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。 getServer(loadBalancer)利用内置的负载均衡算法从服务列表中选择一个。本例中可以看到获取了8082端口的服务 放行后再次访问并跟踪发现获取的是8081 果然实现了负载均衡。 3负载均衡策略IRule 在刚才的代码中可以看到获取服务使通过一个getServer方法来做负载均衡: 我们继续跟入 继续跟踪源码chooseServer方法发现这么一段代码 我们看看这个rule是谁 这里的rule默认值是一个RoundRobinRule看类的介绍 这不就是轮询的意思嘛。 到这里整个负载均衡的流程我们就清楚了。 4总结 SpringCloudRibbon的底层采用了一个拦截器拦截了RestTemplate发出的请求对地址做了修改。用一幅图来总结一下 基本流程如下 拦截我们的RestTemplate请求http://userservice/user/1 RibbonLoadBalancerClient会从请求url中获取服务名称也就是user-service DynamicServerListLoadBalancer根据user-service到eureka拉取服务列表 eureka返回列表localhost:8081、localhost:8082 IRule利用内置负载均衡规则从列表中选择一个例如localhost:8081 RibbonLoadBalancerClient修改请求地址用localhost:8081替代userservice得到http://localhost:8081/user/1发起真实请求 4.3.负载均衡策略 4.3.1.负载均衡策略 负载均衡的规则都定义在IRule接口中而IRule有很多不同的实现类 不同规则的含义如下 内置负载均衡规则类 规则描述 RoundRobinRule 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 AvailabilityFilteringRule 对以下两种服务器进行忽略 1在默认情况下这台服务器如果3次连接失败这台服务器就会被设置为“短路”状态。短路状态将持续30秒如果再次连接失败短路的持续时间就会几何级地增加。 2并发数过高的服务器。如果一个服务器的并发连接数过高配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限可以由客户端的..ActiveConnectionsLimit属性进行配置。 WeightedResponseTimeRule 为每一个服务器赋予一个权重值。服务器响应时间越长这个服务器的权重就越小。这个规则会随机选择服务器这个权重值会影响服务器的选择。 ZoneAvoidanceRule 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。 BestAvailableRule 忽略那些短路的服务器并选择并发数较低的服务器。 RandomRule 随机选择一个可用的服务器。 RetryRule 重试机制的选择逻辑 默认的实现就是ZoneAvoidanceRule是一种轮询方案 4.3.2.自定义负载均衡策略 通过定义IRule实现可以修改负载均衡规则有两种方式 代码方式在order-service中的OrderApplication类中定义一个新的IRule Bean public IRule randomRule(){return new RandomRule(); } 配置文件方式在order-service的application.yml文件中添加新的配置也可以修改规则 复制  userservice: # 给某个微服务配置负载均衡规则这里是userservice服务ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 4.4.饥饿加载 Ribbon默认是采用懒加载即第一次访问时才会去创建LoadBalanceClient请求时间会很长。 而饥饿加载则会在项目启动时创建降低第一次访问的耗时通过下面配置开启饥饿加载 ribbon:eager-load:enabled: trueclients: userservice 5.Nacos注册中心 国内公司一般都推崇阿里巴巴的技术比如注册中心SpringCloudAlibaba也推出了一个名为Nacos的注册中心。 5.1.认识和安装Nacos Nacos是阿里巴巴的产品现在是 SpringCloud中的一个组件。相比 Eureka功能更加丰富在国内受欢迎程度较高。 安装方式参考 Nacos安装指南 5.2.服务注册到nacos Nacos是SpringCloudAlibaba的组件而SpringCloudAlibaba也遵循SpringCloud中定义的服务注册、服务发现规范。因此使用Nacos和使用Eureka对于微服务来说并没有太大区别。 主要差异在于 依赖不同 服务地址不同 1引入依赖 在cloud-demo父工程的pom文件中的dependencyManagement中引入SpringCloudAlibaba的依赖 dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-dependencies/artifactIdversion2.2.6.RELEASE/versiontypepom/typescopeimport/scope /dependency 然后在user-service和order-service中的pom文件中引入nacos-discovery依赖 dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency注意不要忘了注释掉eureka的依赖 2配置nacos地址 在user-service和order-service的application.yml中添加nacos地址 spring:cloud:nacos:server-addr: localhost:8848 注意不要忘了注释掉eureka的地址 3重启 重启微服务后登录nacos管理页面可以看到微服务信息 5.3.服务分级存储模型 一个服务可以有多个实例例如我们的user-service可以有: 127.0.0.1:8081 127.0.0.1:8082 127.0.0.1:8083 假如这些实例分布于全国各地的不同机房例如 127.0.0.1:8081在上海机房 127.0.0.1:8082在上海机房 127.0.0.1:8083在杭州机房 Nacos就将同一机房内的实例 划分为一个集群。 也就是说user-service是服务一个服务可以包含多个集群如杭州、上海每个集群下可以有多个实例形成分级模型如图 微服务互相访问时应该尽可能访问同集群实例因为本地访问速度更快。当本集群内不可用时才访问其它集群。例如 杭州机房内的order-service应该优先访问同机房的user-service。 5.3.1.给user-service配置集群 修改user-service的application.yml文件添加集群配置 spring:cloud:nacos:server-addr: localhost:8848discovery:cluster-name: HZ # 集群名称 重启两个user-service实例后我们可以在nacos控制台看到下面结果 我们再次复制一个user-service启动配置添加属性 -Dserver.port8083 -Dspring.cloud.nacos.discovery.cluster-nameSH 配置如图所示 启动UserApplication3后再次查看nacos控制台 5.3.2.同集群优先的负载均衡 默认的ZoneAvoidanceRule并不能实现根据同集群优先来实现负载均衡。 因此Nacos中提供了一个NacosRule的实现可以优先从同集群中挑选实例。 1给order-service配置集群信息 修改order-service的application.yml文件添加集群配置 spring:cloud:nacos:server-addr: localhost:8848discovery:cluster-name: HZ # 集群名称 2修改负载均衡规则 修改order-service的application.yml文件修改负载均衡规则 userservice:ribbon:NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则5.4.权重配置 实际部署中会出现这样的场景 服务器设备性能有差异部分实例所在机器性能较好另一些较差我们希望性能好的机器承担更多的用户请求。 但默认情况下NacosRule是同集群内随机挑选不会考虑机器的性能问题。 因此Nacos提供了权重配置来控制访问频率权重越大则访问频率越高。 在nacos控制台找到user-service的实例列表点击编辑即可修改权重 在弹出的编辑窗口修改权重 注意如果权重修改为0则该实例永远不会被访问 5.5.环境隔离 Nacos提供了namespace来实现环境隔离功能。 nacos中可以有多个namespace namespace下可以有group、service等 不同namespace之间相互隔离例如不同namespace的服务互相不可见 5.5.1.创建namespace 默认情况下所有service、data、group都在同一个namespace名为public 我们可以点击页面新增按钮添加一个namespace 然后填写表单 就能在页面看到一个新的namespace 5.5.2.给微服务配置namespace 给微服务配置namespace只能通过修改配置来实现。 例如修改order-service的application.yml文件 spring:cloud:nacos:server-addr: localhost:8848discovery:cluster-name: HZnamespace: 492a7d5d-237b-46a1-a99a-fa8e98e4b0f9 # 命名空间填ID重启order-service后访问控制台可以看到下面的结果 此时访问order-service因为namespace不同会导致找不到userservice控制台会报错 5.6.Nacos与Eureka的区别 Nacos的服务实例分为两种l类型 临时实例如果实例宕机超过一定时间会从服务列表剔除默认的类型。 非临时实例如果实例宕机不会从服务列表剔除也可以叫永久实例。 配置一个服务实例为永久实例 spring:cloud:nacos:discovery:ephemeral: false # 设置为非临时实例Nacos和Eureka整体结构类似服务注册、服务拉取、心跳等待但是也存在一些差异 Nacos与eureka的共同点 都支持服务注册和服务拉取 都支持服务提供者心跳方式做健康检测 Nacos与Eureka的区别 Nacos支持服务端主动检测提供者状态临时实例采用心跳模式非临时实例采用主动检测模式 临时实例心跳不正常会被剔除非临时实例则不会被剔除 Nacos支持服务列表变更的消息推送模式服务列表更新更及时 Nacos集群默认采用AP方式当集群中存在非临时实例时采用CP模式Eureka采用AP方式 6.Nacos配置管理 Nacos除了可以做注册中心同样可以做配置管理来使用。 6.1.统一配置管理 当微服务部署的实例越来越多达到数十、数百时逐个修改微服务配置就会让人抓狂而且很容易出错。我们需要一种统一配置管理方案可以集中管理所有实例的配置。 Nacos一方面可以将配置集中管理另一方可以在配置变更时及时通知微服务实现配置的热更新。 1.1.1.在nacos中添加配置文件 如何在nacos中管理配置呢 然后在弹出的表单中填写配置信息 注意项目的核心配置需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。 1.1.2.从微服务拉取配置 微服务要拉取nacos中管理的配置并且与本地的application.yml配置合并才能完成项目启动。 但如果尚未读取application.yml又如何得知nacos地址呢 因此spring引入了一种新的配置文件bootstrap.yaml/bootstrap.yml文件会在application.yml之前被读取流程如下 1引入nacos-config依赖 首先在user-service服务中引入nacos-config的客户端依赖 !--nacos配置管理依赖-- dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId /dependency2添加bootstrap.yaml 然后在user-service中添加一个bootstrap.yaml文件内容如下 spring:application:name: userservice # 服务名称profiles:active: dev #开发环境这里是dev cloud:nacos:server-addr: localhost:8848 # Nacos地址config:file-extension: yaml # 文件后缀名这里会根据spring.cloud.nacos.server-addr获取nacos地址再根据 ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id来读取配置。 本例中就是去读取userservice-dev.yaml 3读取nacos配置 在user-service中的UserController中添加业务逻辑读取pattern.dateformat配置 完整代码 package cn.itcast.user.web;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.web.bind.annotation.*;import java.time.LocalDateTime; import java.time.format.DateTimeFormatter;Slf4j RestController RequestMapping(/user) public class UserController {Autowiredprivate UserService userService;Value(${pattern.dateformat})private String dateformat;GetMapping(now)public String now(){return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));}// ...略 } 在页面访问可以看到效果 1.2.配置热更新 我们最终的目的是修改nacos中的配置后微服务中无需重启即可让配置生效也就是配置热更新。 要实现配置热更新可以使用两种方式 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.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.time.LocalDateTime; import java.time.format.DateTimeFormatter;Slf4j RestController RequestMapping(/user) public class UserController {Autowiredprivate UserService userService;Autowiredprivate PatternProperties patternProperties;GetMapping(now)public String now(){return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));}// 略 } 1.3.配置共享 其实微服务启动时会去nacos读取多个配置文件例如 [spring.application.name]-[spring.profiles.active].yaml例如userservice-dev.yaml [spring.application.name].yaml例如userservice.yaml 而[spring.application.name].yaml不包含环境因此可以被多个环境共享。 下面我们通过案例来测试配置共享 1添加一个环境共享配置 我们在nacos中添加一个userservice.yaml文件 2在user-service中读取共享配置 在user-service服务中修改PatternProperties类读取新添加的属性 在user-service服务中修改UserController添加一个方法 3运行两个UserApplication使用不同的profile 修改UserApplication2这个启动项改变其profile值 这样UserApplication(8081)使用的profile是devUserApplication2(8082)使用的profile是test。 启动UserApplication和UserApplication2 访问http://localhost:8081/user/prop结果 访问http://localhost:8082/user/prop结果 可以看出来不管是dev还是test环境都读取到了envSharedValue这个属性的值。 4配置共享的优先级 当nacos、服务本地同时出现相同属性时优先级有高低之分 1.4.搭建Nacos集群 Nacos生产环境下一定要部署为集群状态部署方式参考 Nacos集群部署 2.Feign远程调用 先来看我们以前利用RestTemplate发起远程调用的代码 存在下面的问题 代码可读性差编程体验不统一 参数复杂URL难以维护 Feign是一个声明式的http客户端官方地址https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现http请求的发送解决上面提到的问题。 2.1.Feign替代RestTemplate Fegin的使用步骤如下 1引入依赖 我们在order-service服务的pom文件中引入feign的依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId /dependency2添加注解 在order-service的启动类添加注解开启Feign的功能 3编写Feign的客户端 在order-service中新建一个接口内容如下 package cn.itcast.order.client;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(userservice) public interface UserClient {GetMapping(/user/{id})User findById(PathVariable(id) Long id); }这个客户端主要是基于SpringMVC的注解来声明远程调用的信息比如 服务名称userservice 请求方式GET 请求路径/user/{id} 请求参数Long id 返回值类型User 这样Feign就可以帮助我们发送http请求无需自己使用RestTemplate来发送了。 4测试 修改order-service中的OrderService类中的queryOrderById方法使用Feign客户端代替RestTemplate 是不是看起来优雅多了。 5总结 使用Feign的步骤 ① 引入依赖 ② 添加EnableFeignClients注解 ③ 编写FeignClient接口 ④ 使用FeignClient中定义的方法代替RestTemplate 2.2.自定义配置 Feign可以支持很多的自定义配置如下表所示 一般情况下默认值就能满足我们使用如果要自定义时只需要创建自定义的Bean覆盖默认Bean即可。 下面以日志为例来演示如何自定义配置。 2.2.1.配置文件方式 基于配置文件修改feign的日志级别可以针对单个服务 feign:  client:config: userservice: # 针对某个微服务的配置loggerLevel: FULL #  日志级别也可以针对所有服务 feign:  client:config: default: # 这里用default就是全局配置如果是写服务名称则是针对某个微服务的配置loggerLevel: FULL #  日志级别而日志的级别分为四种 NONE不记录任何日志信息这是默认值。 BASIC仅记录请求的方法URL以及响应状态码和执行时间 HEADERS在BASIC的基础上额外记录了请求和响应的头信息 FULL记录所有请求和响应的明细包括头信息、请求体、元数据。 2.2.2.Java代码方式 也可以基于Java代码来修改日志级别先声明一个类然后声明一个Logger.Level的对象 public class DefaultFeignConfiguration  {Beanpublic Logger.Level feignLogLevel(){return Logger.Level.BASIC; // 日志级别为BASIC} }如果要全局生效将其放到启动类的EnableFeignClients这个注解中 EnableFeignClients(defaultConfiguration DefaultFeignConfiguration .class) 1. 如果是局部生效则把它放到对应的FeignClient这个注解中 FeignClient(value userservice, configuration DefaultFeignConfiguration .class) 1. 2.3.Feign使用优化 Feign底层发起http请求依赖于其它的框架。其底层客户端实现包括 •URLConnection默认实现不支持连接池 •Apache HttpClient 支持连接池 •OKHttp支持连接池 因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。 这里我们用Apache的HttpClient来演示。 1引入依赖 在order-service的pom文件中引入Apache的HttpClient依赖 !--httpClient的依赖 -- dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-httpclient/artifactId /dependency2配置连接池 在order-service的application.yml中添加配置 feign:client:config:default: # default全局的配置loggerLevel: BASIC # 日志级别BASIC就是基本的请求和响应信息httpclient:enabled: true # 开启feign对HttpClient的支持max-connections: 200 # 最大的连接数max-connections-per-route: 50 # 每个路径的最大连接数接下来在FeignClientFactoryBean中的loadBalance方法中打断点 Debug方式启动order-service服务可以看到这里的client底层就是Apache HttpClient 总结Feign的优化 1.日志级别尽量用basic 2.使用HttpClient或OKHttp代替URLConnection ① 引入feign-httpClient依赖 ② 配置文件开启httpClient功能设置连接池参数 2.4.最佳实践 所谓最近实践就是使用过程中总结的经验最好的一种使用方式。 自习观察可以发现Feign的客户端与服务提供者的controller代码非常相似 feign客户端 UserController 有没有一种办法简化这种重复的代码编写呢 2.4.1.继承方式 一样的代码可以通过继承来共享 1定义一个API接口利用定义方法并基于SpringMVC注解做声明。 2Feign客户端和Controller都集成改接口 优点 简单 实现了代码共享 缺点 服务提供方、服务消费方紧耦合 参数列表中的注解映射并不会继承因此Controller中必须再次声明方法、参数列表、注解 2.4.2.抽取方式 将Feign的Client抽取为独立模块并且把接口有关的POJO、默认的Feign配置都放到这个模块中提供给所有消费者使用。 例如将UserClient、User、Feign的默认配置都抽取到一个feign-api包中所有微服务引用该依赖包即可直接使用。 2.4.3.实现基于抽取的最佳实践 1抽取 首先创建一个module命名为feign-api 项目结构 在feign-api中然后引入feign的starter依赖 dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId /dependency然后order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中 2在order-service中使用feign-api 首先删除order-service中的UserClient、User、DefaultFeignConfiguration等类或接口。 在order-service的pom文件中中引入feign-api的依赖 dependencygroupIdcn.itcast.demo/groupIdartifactIdfeign-api/artifactIdversion1.0/version /dependency修改order-service中的所有与上述三个组件有关的导包部分改成导入feign-api中的包 3重启测试 重启后发现服务报错了 这是因为UserClient现在在cn.itcast.feign.clients包下 而order-service的EnableFeignClients注解是在cn.itcast.order包下不在同一个包无法扫描到UserClient。 4解决扫描包问题 方式一 指定Feign应该扫描的包 EnableFeignClients(basePackages cn.itcast.feign.clients)   方式二 指定需要加载的Client接口 EnableFeignClients(clients {UserClient.class})   3.Gateway服务网关 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目该项目是基于 Spring 5.0Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。 3.1.为什么需要网关 Gateway网关是我们服务的守门神所有微服务的统一入口。 网关的核心功能特性 请求路由 权限控制 限流 架构图 权限控制网关作为微服务入口需要校验用户是是否有请求资格如果没有则进行拦截。 路由和负载均衡一切请求都必须先经过gateway但网关不处理业务而是根据某种规则把请求转发到某个微服务这个过程叫做路由。当然路由的目标服务有多个时还需要做负载均衡。 限流当请求流量过高时在网关中按照下流的微服务能够接受的速度来放行请求避免服务压力过大。 在SpringCloud中网关的实现包括两种 gateway zuul Zuul是基于Servlet的实现属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux属于响应式编程的实现具备更好的性能。 3.2.gateway快速入门 下面我们就演示下网关的基本路由功能。基本步骤如下 创建SpringBoot工程gateway引入网关依赖 编写启动类 编写基础配置和路由规则 启动网关服务进行测试 1创建gateway服务引入依赖 创建服务 引入依赖 !--网关-- dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-gateway/artifactId /dependency !--nacos服务发现依赖-- dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-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://userservicelb是负载均衡根据服务名拉取服务列表实现负载均衡。 4重启测试 重启网关访问http://localhost:10010/user/1时符合/user/**规则请求转发到urihttp://userservice/user/1得到了结果 5网关路由的流程图 整个访问的流程如下 总结 网关搭建步骤 创建项目引入nacos服务发现和gateway依赖 配置application.yml包括服务基本信息、nacos地址、路由 路由配置包括 路由id路由的唯一标示 路由目标uri路由的目标地址http代表固定地址lb代表根据服务名负载均衡 路由断言predicates判断路由的规则 路由过滤器filters对请求或响应做处理 接下来就重点来学习路由断言和路由过滤器的详细知识 3.3.断言工厂 我们在配置文件中写的断言规则只是字符串这些字符串会被Predicate Factory读取并处理转变为路由判断的条件 例如Path/user/**是按照路径匹配这个规则是由 org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来 处理的像这样的断言工厂在SpringCloudGateway还有十几个: 我们只需要掌握Path这种路由方式就可以了。 3.4.过滤器工厂 GatewayFilter是网关中提供的一种过滤器可以对进入网关的请求和微服务返回的响应做处理 3.4.1.路由过滤器的种类 Spring提供了31种不同的路由过滤器工厂。例如 3.4.2.请求头过滤器 下面我们以AddRequestHeader 为例来讲解。 需求给所有进入userservice的请求添加一个请求头Truthitcast is freaking awesome! 只需要修改gateway服务的application.yml文件添加路由过滤即可 spring:cloud:gateway:routes:- id: user-service uri: lb://userservice predicates: - Path/user/** filters: # 过滤器- AddRequestHeaderTruth, Itcast is freaking awesome! # 添加请求头 当前过滤器写在userservice路由下因此仅仅对访问userservice的请求有效。 3.4.3.默认过滤器 如果要对所有的路由都生效则可以将过滤器工厂写到default下。格式如下 spring:cloud:gateway:routes:- id: user-service uri: lb://userservice predicates: - Path/user/**default-filters: # 默认过滤项- AddRequestHeaderTruth, Itcast is freaking awesome!3.4.4.总结 过滤器的作用是什么 ① 对路由的请求或响应做加工处理比如添加请求头 ② 配置在路由下的过滤器只对当前路由的请求生效 defaultFilters的作用是什么 ① 对所有路由都生效的过滤器 3.5.全局过滤器 在Gateway过滤器网关提供了31种但每一种过滤器的作用都是固定的。如果我们希望拦截请求做自己的业务逻辑则没办法实现。 3.5.1.全局过滤器作用 全局过滤器的作用也是处理一切进入网关的请求和微服务响应与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义处理逻辑是固定的而GlobalFilter的逻辑需要自己写代码实现。 定义方式是实现GlobalFilter接口。 public interface GlobalFilter {/***  处理当前请求有必要的话通过{link GatewayFilterChain}将请求交给下一个过滤器处理** param exchange 请求上下文里面可以获取Request、Response等信息* param chain 用来把请求委托给下一个过滤器 * return {code MonoVoid} 返回标示当前过滤器业务结束*/MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain); }在filter中编写自定义逻辑可以实现下列功能 登录状态判断 权限校验 请求限流等 3.5.2.自定义全局过滤器 需求定义全局过滤器拦截请求判断请求的参数是否满足下面条件 参数中是否有authorization authorization参数值是否为admin 如果同时满足则放行否则拦截 实现 在gateway中定义一个过滤器   package cn.itcast.gateway.filters;import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono;Order(-1) Component public class AuthorizeFilter implements GlobalFilter {Overridepublic MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 1.获取请求参数MultiValueMapString, String params exchange.getRequest().getQueryParams();// 2.获取authorization参数String auth params.getFirst(authorization);// 3.校验if (admin.equals(auth)) {// 放行return chain.filter(exchange);}// 4.拦截// 4.1.禁止访问设置状态码exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);// 4.2.结束处理return exchange.getResponse().setComplete();} } 3.5.3.过滤器执行顺序 请求进入网关会碰到三类过滤器当前路由的过滤器、DefaultFilter、GlobalFilter 请求路由后会将当前路由过滤器和DefaultFilter、GlobalFilter合并到一个过滤器链集合中排序后依次执行每个过滤器 排序的规则是什么呢 每一个过滤器都必须指定一个int类型的order值order值越小优先级越高执行顺序越靠前。 GlobalFilter通过实现Ordered接口或者添加Order注解来指定order值由我们自己指定 路由过滤器和defaultFilter的order由Spring指定默认是按照声明顺序从1递增。 当过滤器的order值一样时会按照 defaultFilter 路由过滤器 GlobalFilter的顺序执行。 详细内容可以查看源码 org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法是先加载defaultFilters然后再加载某个route的filters然后合并。 org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器与前面的过滤器合并后根据order排序组织过滤器链 3.6.跨域问题 3.6.1.什么是跨域问题 跨域域名不一致就是跨域主要包括 域名不同 www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com 域名相同端口不同localhost:8080和localhost8081 跨域问题浏览器禁止请求的发起者与服务端发生跨域ajax请求请求被浏览器拦截的问题 解决方案CORS这个以前应该学习过这里不再赘述了。不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html 3.6.2.模拟跨域问题 找到资料的页面文件 放入tomcat或者nginx这样的web服务器中启动并访问。 可以在浏览器控制台看到下面的错误 从localhost:8090访问localhost:10010端口不同显然是跨域的请求。 3.6.3.解决跨域问题 在gateway服务的application.yml文件中添加下面的配置 spring:cloud:gateway:# 。。。globalcors: # 全局的跨域处理add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题corsConfigurations:[/**]:allowedOrigins: # 允许哪些网站的跨域请求 - http://localhost:8090allowedMethods: # 允许的跨域ajax的请求方式- GET- POST- DELETE- PUT- OPTIONSallowedHeaders: * # 允许在请求中携带的头信息allowCredentials: true # 是否允许携带cookiemaxAge: 360000 # 这次跨域检测的有效期
http://www.w-s-a.com/news/14533/

相关文章:

  • 网络小说网站推广策划方案单位网站建设收费标准
  • 医院网站建设论证报告河源网站seo
  • 网站demo怎么做淘宝客网站一般用什么做的
  • 网站开发之美 pdf关键词查询优化
  • 可以建站的网站做一个网站美工多少钱
  • 怎么做网站专题互联网营销师报考费用
  • 淘宝导购网站怎么做上海数据开放网站建设
  • 广东网站建设怎么选2021个人网站盈利模式
  • 珠海网站建设的公司排名网站前端开发培训
  • 手机网站制作 费怎么做分录网站域名hk
  • 济南做网站建网站公司怎样用代码制作网站
  • 网站开发文档有哪些建设规划
  • 专注网站建设11年百度搜索不到我的网站
  • 企业网站 建设 流程wordpress 分类目录自定义
  • 北京市建设管理公司网站长春网站推广排名
  • 西安建站软件获取网站全站代码
  • 个人做网站怎么备案网站建设收费标准渠道
  • 单位做网站注意什么问题如何修改单页网站
  • asp全静态企业网站wordpress文章封面
  • 电白区住房和城乡建设部门户网站免费公司网站模版
  • 做玩游戏任务得q币的网站如何制作自己的公司内部网站
  • 网站优化自己可以做吗非官方网站建设
  • 厦门邮件网站点击网站
  • 网络推广网站的方法亳州网站制作公司
  • 网站域名主机空间区别广告设计专业前景
  • 新手做啥网站好dedecms网站的源码如何安装
  • 哪些网站是用iframe免费网站域名查询
  • 自己开的网站 可以做代销吗百度查找相似图片
  • 网站建设设计作业网站备案渝
  • 中国重庆网站建设福州短视频seo获客