96SEO 2026-02-20 07:46 0
当微服务部署的实例越来越多#xff0c;达到数十、数百时#xff0c;逐个修改微服务配置就会让人抓狂#xff0c;而且很容易出错。

我…SpringCloud实用篇02
当微服务部署的实例越来越多达到数十、数百时逐个修改微服务配置就会让人抓狂而且很容易出错。
我们需要一种统一配置管理方案可以集中管理所有实例的配置。
Nacos一方面可以将配置集中管理另一方可以在配置变更时及时通知微服务实现配置的热更新。
注意项目的核心配置需要热更新的配置才有放到nacos管理的必要。
基本不会变更的一些配置还是保存在微服务本地比较好。
微服务要拉取nacos中管理的配置并且与本地的application.yml配置合并才能完成项目启动。
但如果尚未读取application.yml又如何得知nacos地址呢
因此spring引入了一种新的配置文件bootstrap.yaml文件会在application.yml之前被读取流程如下
首先在user-service服务中引入nacos-config的客户端依赖
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-config/artifactId
然后在user-service中添加一个bootstrap.yaml文件内容如下
文件后缀名这里会根据spring.cloud.nacos.server-addr获取nacos地址再根据
${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}作为文件id来读取配置。
在user-service中的UserController中添加业务逻辑读取pattern.dateformat配置
cn.itcast.user.service.UserService;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.beans.factory.annotation.Value;
org.springframework.web.bind.annotation.*;import
java.time.format.DateTimeFormatter;Slf4j
userService;Value(${pattern.dateformat})private
dateformat;GetMapping(now)public
LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));}//
我们最终的目的是修改nacos中的配置后微服务中无需重启即可让配置生效也就是配置热更新。
在Value注入的变量所在类上添加注解RefreshScope
使用ConfigurationProperties注解代替Value注解。
在user-service服务中添加一个类读取patterrn.dateformat属性
org.springframework.boot.context.properties.ConfigurationProperties;
org.springframework.stereotype.Component;Component
cn.itcast.user.config.PatternProperties;
cn.itcast.user.service.UserService;
org.springframework.beans.factory.annotation.Autowired;
org.springframework.web.bind.annotation.GetMapping;
org.springframework.web.bind.annotation.PathVariable;
org.springframework.web.bind.annotation.RequestMapping;
org.springframework.web.bind.annotation.RestController;import
java.time.format.DateTimeFormatter;Slf4j
patternProperties;GetMapping(now)public
LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));}//
[spring.application.name]-[spring.profiles.active].yaml例如userservice-dev.yaml
[spring.application.name].yaml例如userservice.yaml
而[spring.application.name].yaml不包含环境因此可以被多个环境共享。
我们在nacos中添加一个userservice.yaml文件
在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这个属性的值。
Nacos生产环境下一定要部署为集群状态部署方式参考课前资料中的文档
Feign是一个声明式的http客户端官方地址https://github.com/OpenFeign/feign
其作用就是帮助我们优雅的实现http请求的发送解决上面提到的问题。
我们在order-service服务的pom文件中引入feign的依赖
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId
在order-service的启动类添加注解开启Feign的功能
org.springframework.cloud.openfeign.FeignClient;
org.springframework.web.bind.annotation.GetMapping;
org.springframework.web.bind.annotation.PathVariable;FeignClient(userservice)
}这个客户端主要是基于SpringMVC的注解来声明远程调用的信息比如
服务名称userservice请求方式GET请求路径/user/{id}请求参数Long
这样Feign就可以帮助我们发送http请求无需自己使用RestTemplate来发送了。
修改order-service中的OrderService类中的queryOrderById方法使用Feign客户端代替RestTemplate
使用FeignClient中定义的方法代替RestTemplate
类型作用说明feign.Logger.Level修改日志级别包含四种不同的级别NONE、BASIC、HEADERS、FULLfeign.codec.Decoder响应结果的解析器http远程调用的结果做解析例如解析json字符串为java对象feign.codec.Encoder请求参数编码将请求参数编码便于通过http请求发送feign.
Contract支持的注解格式默认是SpringMVC的注解feign.
Retryer失败重试机制请求失败的重试机制默认是没有不过会使用Ribbon的重试
一般情况下默认值就能满足我们使用如果要自定义时只需要创建自定义的Bean覆盖默认Bean即可。
这里用default就是全局配置如果是写服务名称则是针对某个微服务的配置loggerLevel:
NONE不记录任何日志信息这是默认值。
BASIC仅记录请求的方法URL以及响应状态码和执行时间HEADERS在BASIC的基础上额外记录了请求和响应的头信息FULL记录所有请求和响应的明细包括头信息、请求体、元数据。
也可以基于Java代码来修改日志级别先声明一个类然后声明一个Logger.Level的对象
}如果要全局生效将其放到启动类的EnableFeignClients这个注解中
EnableFeignClients(defaultConfiguration
如果是局部生效则把它放到对应的FeignClient这个注解中
Feign底层发起http请求依赖于其它的框架。
其底层客户端实现包括
因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。
在order-service的pom文件中引入Apache的HttpClient依赖
dependencygroupIdio.github.openfeign/groupIdartifactIdfeign-httpclient/artifactId
在order-service的application.yml中添加配置
日志级别BASIC就是基本的请求和响应信息httpclient:enabled:
开启feign对HttpClient的支持max-connections:
最大的连接数max-connections-per-route:
每个路径的最大连接数接下来在FeignClientFactoryBean中的loadBalance方法中打断点
Debug方式启动order-service服务可以看到这里的client底层就是Apache
2.使用HttpClient或OKHttp代替URLConnection
自习观察可以发现Feign的客户端与服务提供者的controller代码非常相似
1定义一个API接口利用定义方法并基于SpringMVC注解做声明。
参数列表中的注解映射并不会继承因此Controller中必须再次声明方法、参数列表、注解
将Feign的Client抽取为独立模块并且把接口有关的POJO、默认的Feign配置都放到这个模块中提供给所有消费者使用。
例如将UserClient、User、Feign的默认配置都抽取到一个feign-api包中所有微服务引用该依赖包即可直接使用。
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-openfeign/artifactId
/dependency然后order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到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中的包
这是因为UserClient现在在cn.itcast.feign.clients包下
而order-service的EnableFeignClients注解是在cn.itcast.order包下不在同一个包无法扫描到UserClient。
EnableFeignClients(basePackages
{UserClient.class})3.Gateway服务网关
等响应式编程和事件流技术开发的网关它旨在为微服务架构提供一种简单有效的统一的
权限控制网关作为微服务入口需要校验用户是是否有请求资格如果没有则进行拦截。
路由和负载均衡一切请求都必须先经过gateway但网关不处理业务而是根据某种规则把请求转发到某个微服务这个过程叫做路由。
当然路由的目标服务有多个时还需要做负载均衡。
限流当请求流量过高时在网关中按照下流的微服务能够接受的速度来放行请求避免服务压力过大。
Zuul是基于Servlet的实现属于阻塞式编程。
而SpringCloudGateway则是基于Spring5中提供的WebFlux属于响应式编程的实现具备更好的性能。
创建SpringBoot工程gateway引入网关依赖编写启动类编写基础配置和路由规则启动网关服务进行测试
dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-gateway/artifactId
dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId
org.springframework.boot.SpringApplication;
org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
{SpringApplication.run(GatewayApplication.class,
这个是按照路径匹配只要以/user/开头就符合要求我们将符合Path
/user/**开头的请求代理到lb://userservicelb是负载均衡根据服务名拉取服务列表实现负载均衡。
重启网关访问http://localhost:10010/user/1时符合/user/**规则请求转发到urihttp://userservice/user/1得到了结果
配置application.yml包括服务基本信息、nacos地址、路由
路由目标uri路由的目标地址http代表固定地址lb代表根据服务名负载均衡
我们在配置文件中写的断言规则只是字符串这些字符串会被Predicate
org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来
处理的像这样的断言工厂在SpringCloudGateway还有十几个:
After2037-01-20T17:42:47.789-07:00[America/Denver]Before是某个时间点之前的请求-
Before2031-04-13T15:14:47.43308:00[Asia/Shanghai]Between是某两个时间点之前的请求-
Between2037-01-20T17:42:47.789-07:00[America/Denver],
2037-01-21T17:42:47.789-07:00[America/Denver]Cookie请求必须包含某些cookie-
Host.somehost.org,.anotherhost.orgMethod请求方式必须是指定方式-
MethodGET,POSTPath请求路径必须符合指定规则-
Path/red/{segment},/blue/**Query请求参数必须包含指定参数-
QuerynameRemoteAddr请求者的ip必须是指定范围-
RemoteAddr192.168.1.1/24Weight权重处理
GatewayFilter是网关中提供的一种过滤器可以对进入网关的请求和微服务返回的响应做处理
名称说明AddRequestHeader给当前请求添加一个请求头RemoveRequestHeader移除请求中的一个请求头AddResponseHeader给响应结果中添加一个响应头RemoveResponseHeader从响应结果中移除有一个响应头RequestRateLimiter限制请求的流量
需求给所有进入userservice的请求添加一个请求头Truthitcast
只需要修改gateway服务的application.yml文件添加路由过滤即可
添加请求头当前过滤器写在userservice路由下因此仅仅对访问userservice的请求有效。
如果要对所有的路由都生效则可以将过滤器工厂写到default下。
格式如下
上一节学习的过滤器网关提供了31种但每一种过滤器的作用都是固定的。
如果我们希望拦截请求做自己的业务逻辑则没办法实现。
全局过滤器的作用也是处理一切进入网关的请求和微服务响应与GatewayFilter的作用一样。
区别在于GatewayFilter通过配置定义处理逻辑是固定的而GlobalFilter的逻辑需要自己写代码实现。
GatewayFilterChain}将请求交给下一个过滤器处理**
请求上下文里面可以获取Request、Response等信息*
cn.itcast.gateway.filters;import
org.springframework.cloud.gateway.filter.GatewayFilterChain;
org.springframework.cloud.gateway.filter.GlobalFilter;
org.springframework.core.annotation.Order;
org.springframework.http.HttpStatus;
org.springframework.stereotype.Component;
org.springframework.web.server.ServerWebExchange;
reactor.core.publisher.Mono;Order(-1)
exchange.getRequest().getQueryParams();//
params.getFirst(authorization);//
4.1.禁止访问设置状态码exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);//
exchange.getResponse().setComplete();}
请求进入网关会碰到三类过滤器当前路由的过滤器、DefaultFilter、GlobalFilter
请求路由后会将当前路由过滤器和DefaultFilter、GlobalFilter合并到一个过滤器链集合中排序后依次执行每个过滤器
每一个过滤器都必须指定一个int类型的order值order值越小优先级越高执行顺序越靠前。
GlobalFilter通过实现Ordered接口或者添加Order注解来指定order值由我们自己指定路由过滤器和defaultFilter的order由Spring指定默认是按照声明顺序从1递增。
当过滤器的order值一样时会按照
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters()方法是先加载defaultFilters然后再加载某个route的filters然后合并。
org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()方法会加载全局过滤器与前面的过滤器合并后根据order排序组织过滤器链
域名相同端口不同localhost:8080和localhost8081
跨域问题浏览器禁止请求的发起者与服务端发生跨域ajax请求请求被浏览器拦截的问题
解决方案CORS这个以前应该学习过这里不再赘述了。
不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html
放入tomcat或者nginx这样的web服务器中启动并访问。
从localhost:8090访问localhost:10010端口不同显然是跨域的请求。
在gateway服务的application.yml文件中添加下面的配置
全局的跨域处理add-to-simple-url-handler-mapping:
解决options请求被拦截问题corsConfigurations:[/**]:allowedOrigins:
http://localhost:8090allowedMethods:
域名相同端口不同localhost:8080和localhost8081
跨域问题浏览器禁止请求的发起者与服务端发生跨域ajax请求请求被浏览器拦截的问题
解决方案CORS这个以前应该学习过这里不再赘述了。
不知道的小伙伴可以查看https://www.ruanyifeng.com/blog/2016/04/cors.html
[外链图片转存中…(img-2VAcm9x4-1700399918824)]
放入tomcat或者nginx这样的web服务器中启动并访问。
[外链图片转存中…(img-YXFkluoe-1700399918824)]
从localhost:8090访问localhost:10010端口不同显然是跨域的请求。
在gateway服务的application.yml文件中添加下面的配置
全局的跨域处理add-to-simple-url-handler-mapping:
解决options请求被拦截问题corsConfigurations:[/**]:allowedOrigins:
http://localhost:8090allowedMethods:
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback