初始内容
创建gulimall项目删除pom里其他依赖只保留
<name>gulimall</name> <description>谷粒商城-聚合服务</description> <packaging>pom</packaging> <!--依次创建如下的模块--> <modules> <module>gulimall-coupon</module> <module>gulimall-member</module> <module>gulimall-order</module> <module>gulimall-product</module> <module>gulimall-ware</module> <!--权限认证项目直接引入--> <module>renren-fast</module> <!--生成代码--> <module>renren-generator</module> <module>gulimall-common</module> </modules>
准备相关数据库 redis等 可以安装在 云服务器 docker方便些
详情参考从前慢-谷粒商城篇章1
进入分布式微服务学习
1、nacos
1.1服务发现
引入nacos依赖
在common模块pom文件添加
<!--服务注册发现--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--配置中心--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
在各个模块application.yml中添加
#注意缩进 cloud: nacos: discovery: #根据自己的nacos ip以及端口填写 server-addr: 118.190.204.58:8848 application: #服务名称 name: gulimall-xxx
在各个模块的启动类添加@EnableDiscoveryClient注解 高版本也可不添加
测试
运行各个模块
打开浏览器 nacos页面118.190.204.58:8848/nacos 查看 服务列表 是否存在各个模块对应的服务
1.2Feign远程调用
例如会员服务想要远程调用优惠券服务,只需要给会员服务里引入 openfeign依赖,他就有了远程调用其他服务的能力。我们直接在common里添加了openfeign依赖 不必再添加
1
在coupon的controller中修改如下的内容
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;@RequestMapping("/member/list")
public R membercoupons(){ //全系统的所有返回都返回R
// 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回
CouponEntity couponEntity = new CouponEntity();
couponEntity.setCouponName("满100减10");//优惠券的名字
return R.ok().put("coupons",Arrays.asList(couponEntity));
}这样我们准备好了优惠券的调用内容
2
在member的配置类上加注解@EnableFeignClients(basePackages="com.yxj.gulimall.member.feign"),
告诉spring这里面是一个远程调用客户端,member要调用的接口package com.yxj.gulimall.member;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@MapperScan("com.yxj.gulimall.member.dao")
@EnableDiscoveryClient
@EnableFeignClients(basePackages="com.yxj.gulimall.member.feign")
public class GulimallMemberApplication {public static void main(String[] args) {
SpringApplication.run(GulimallMemberApplication.class, args);
}}
3
那么要调用什么东西呢?就是我们刚才写的优惠券的功能,
复制函数部分,在member的com.yxj.gulimall.member包下新建包feign新建类:
package com.yxj.gulimall.member.feign;import com.yxj.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;@FeignClient("gulimall-coupon") //告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法
public interface CouponFeignService {
@RequestMapping("/coupon/coupon/member/list")
public R membercoupons();//得到一个R对象
}
4
然后我们在member的控制层写一个测试请求
@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
private MemberService memberService;@Autowired
CouponFeignService couponFeignService;@RequestMapping("/coupons")
public R test(){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("张三");
R membercoupons = couponFeignService.membercoupons(); //假设张三去数据库查了后返回了张三的优惠券信息// 打印会员和优惠券信息
return R.ok().put("member",memberEntity).put("coupons",membercoupons.get("coupons"));
}
5
重新启动服务访问
http://localhost:8000/member/member/coupons见到
{"msg":"success","code":0,"coupons":[{"id":null,"couponType":null,"couponImg":null,"couponName":"满100减10","num":null,"amount":null,"perLimit":null,"minPoint":null,"startTime":null,"endTime":null,"useType":null,"note":null,"publishCount":null,"useCount":null,"receiveCount":null,"enableStartTime":null,"enableEndTime":null,"code":null,"memberLevel":null,"publish":null}],"member":{"id":null,"levelId":null,"username":null,"password":null,"nickname":"张三","mobile":null,"email":null,"header":null,"gender":null,"birth":null,"city":null,"job":null,"sign":null,"sourceType":null,"integration":null,"growth":null,"status":null,"createTime":null}}测试通过
coupon里的R.ok()是什么 # coupon里的控制层就是new了个couponEntity然后放到hashmap(R)里而已。
public class R extends HashMap<String, Object> {
public static R ok() {
return new R();
}public R put(String key, Object value) {
super.put(key, value);
return this;
}}
1.3配置中心
我们还可以用nacos作为配置中心。配置中心的意思是不在application.properties
等文件中配置了,而是放到nacos配置中心公用,这样无需每台机器都改。1 引入配置中心依赖,放到common中
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2 在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是
springboot里规定的,他优先级别application.properties高
# 改名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=192.168.11.1:88483 @RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;@Value("${coupon.user.name}")//从application.properties中获取//不要写user.name,他是环境里的变量
private String name;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test(){return R.ok().put("name",name).put("age",age);
}}
4 浏览器去nacos里的配置列表,点击+号,data ID:gulimall-coupon.properties,配置
# gulimall-coupon.properties
coupon.user.name="张三"
coupon.user.age=125 然后点击发布。重启coupon,http://localhost:7000/coupon/coupon/test
{"msg":"success","code":0,"name":"张三","age":12}
6 但是修改肿么办?实际生产中不能重启应用。在coupon的控制层上加
@RefreshScope
7 最终代码如下
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;@Value("${coupon.user.name}")//从application.properties中获取//不要写user.name,他是环境里的变量
private String name;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test(){return R.ok().put("name",name).put("age",age);
}}
8 重启后,在nacos浏览器里修改配置,修改就可以观察到能动态修改了
nacos的配置内容优先于项目本地的配置内容。
配置中心进阶 (写配置要注意缩进)
在nacos浏览器中还可以配置:
命名空间:用作配置隔离。(一般每个微服务一个命名空间)
默认public。默认新增的配置都在public空间下
开发、测试、开发可以用命名空间分割。properties每个空间有一份。
在bootstrap.properties里配置
spring.cloud.nacos.config.namespace=b176a68a-6800-4648-833b-be10be8bab00 # 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
也可以为每个微服务配置一个命名空间,微服务互相隔离配置集:一组相关或不相关配置项的集合。
配置集ID:类似于配置文件名,即Data ID
配置分组:默认所有的配置集都属于DEFAULT_GROUP。自己可以创建分组,比如双十一,618,双十二
spring.cloud.nacos.config.group=DEFAULT_GROUP # 更改配置分组
最终方案:每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev/test/prod)加载多配置集
我们要把原来application.yml里的内容都分文件抽离出去。我们在nacos里创建好
后,在coupons里指定要导入的配置即可。bootstrap.properties
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=192.168.11.1:8848
spring.cloud.nacos.config.namespace=ed042b3b-b7f3-4734-bdcb-0c516cb357d7 # # 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
spring.cloud.nacos.config.group=dev # 配置文件所在的组spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=truespring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=truespring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true
datasource.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.103:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: rootmybatis.yml
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: autoother.yml
spring:
application:
name: gulimall-coupon
cloud:
nacos:
discovery:
server-addr: 192.168.11.1:8848server:
port: 7000
注意: 服务发现也可以配置到其他namespace只需要添加红字属性 实现下面效果
cloud:
nacos:
discovery:
server-addr: 118.190.204.58:8848
namespace: f0a89dd0-619a-45c7-b79b-ed63d331e68d
#某些版本不支持group
group: dev