前面两篇讲了不用springcloud做粘合,直接springboot+dubbo+nacos+sentinel的搭建
这篇讲用springcloud做粘合是怎么搞的
场景是business项目调用storage项目
目录
pom.xml
test-spring-cloud-alibaba
com.sid
1.0-SNAPSHOT
4.0.0
business
8
8
org.springframework.boot
spring-boot-starter-web
2.1.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-dubbo
2.1.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.1.1.RELEASE
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
mysql
mysql-connector-java
5.1.46
runtime
com.sid
api
1.0-SNAPSHOT
org.apache.httpcomponents
httpclient
4.5.6
org.springframework.boot
spring-boot-maven-plugin
2.0.1.RELEASE
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.7
${basedir}/src/main/resources/generator/generatorConfig.xml
true
true
mysql
mysql-connector-java
5.1.46
runtime
bootstrap.yml
spring:
application:
name: app-business
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
application.yml
server:
port: 8085
###起个名字作为服务名称(该服务注册到nacos注册中心的名称,比如订单服务)
spring:
application:
name: app-business
datasource:
url: jdbc:mysql://localhost:3306/test-business
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
# Dubbo Application
dubbo:
# Dubbo Protocol
protocol:
name: dubbo
## Random port
port: -1
## Dubbo Registry
registry:
address: spring-cloud://localhost
application:
name: app-business
scan:
#这里是表明RPC接口包的package
base-packages: com.sid.rpc.service
cloud:
#business这个服务需要调用order和storage服务,这个配置表示去订阅他们
subscribed-services: app-order,app-storage
## 该配置节点为独立的节点,不是在在spring的节点下
mybatis:
mapper-locations: classpath:mapping/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.sid.model # 注意:对应实体类的路径
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #控制台打印sql
# log config
logging:
config: classpath:logback-spring.xml
启动类
package com.sid;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
@MapperScan("com.sid.mapper")
public class BusinessApp {
public static void main(String[] args) {
SpringApplication.run(BusinessApp.class, args);
}
}
BusinessServiceImpl.java
该类里面就是用dubbo去RPC调用storage服务和order服务
package com.sid.service;
import com.sid.mapper.BusinessMapper;
import com.sid.model.Business;
import com.sid.rpc.service.model.Order;
import com.sid.rpc.service.service.OrderServiceApi;
import com.sid.rpc.service.service.StorageServiceApi;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
public class BusinessServiceImpl implements BusinessService{
@Reference(check = false,group = "order-provider", version = "1.0.0")
OrderServiceApi orderServiceApi;
@Reference(check = false,group = "storage-provider", version = "1.0.0")
StorageServiceApi storageServiceApi;
@Resource
BusinessMapper businessMapper;
/**
* 采购
*/
@Transactional
@Override
public void purchase(String userId, String commodityCode, int orderCount) {
Business b = new Business();
b.setUserId(userId);
b.setCommodityCode(commodityCode);
b.setOrderCount(orderCount);
int i = businessMapper.insertSelective(b);
String storageDeductResult = storageServiceApi.deduct(commodityCode, orderCount);
System.out.println(storageDeductResult);
Order order = orderServiceApi.create(userId, commodityCode, orderCount);
String orderCreateResult = order.getMsg();
if(!storageDeductResult.equals("success") || !orderCreateResult.equals("success")){
System.out.println("resutl storage service :"+storageDeductResult);
System.out.println("resutl order service :"+orderCreateResult);
throw new RuntimeException("BusinessServiceImpl purchase fail");
}
}
}
目录
pom.xml
test-spring-cloud-alibaba
com.sid
1.0-SNAPSHOT
4.0.0
storage
8
8
org.springframework.boot
spring-boot-starter-web
2.1.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-dubbo
2.1.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.1.1.RELEASE
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
2.1.1.RELEASE
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
mysql
mysql-connector-java
5.1.46
runtime
com.sid
api
1.0-SNAPSHOT
org.apache.httpcomponents
httpclient
4.5.6
org.springframework.boot
spring-boot-maven-plugin
2.0.1.RELEASE
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.7
${basedir}/src/main/resources/generator/generatorConfig.xml
true
true
mysql
mysql-connector-java
5.1.46
runtime
bootstrap.yml
spring:
application:
name: app-storage
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
application.yml
server:
port: 8083
###起个名字作为服务名称(该服务注册到nacos注册中心的名称,比如订单服务)
spring:
application:
name: app-storage
datasource:
url: jdbc:mysql://localhost:3306/test-storage
username: root
password: root
# 使用druid数据源
driver-class-name: com.mysql.jdbc.Driver
cloud:
nacos:
# Nacos 服务发现与注册配置
discovery:
server-addr: localhost:8848
config:
server-addr: localhost:8848
# Dubbo Application
dubbo:
# Dubbo Protocol
protocol:
name: dubbo
## Random port
port: -1
## Dubbo Registry
registry:
# 挂载到 Spring Cloud 注册中心
address: spring-cloud://localhost
application:
name: app-storage
scan:
base-packages: com.sid.rpc.service
## 该配置节点为独立的节点,不是在在spring的节点下
mybatis:
mapper-locations: classpath:mapping/*.xml #注意:一定要对应mapper映射xml文件的所在路径
type-aliases-package: com.sid.model # 注意:对应实体类的路径
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #控制台打印sql
启动类
package com.sid;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.sid.mapper")
@EnableDubbo
public class StorageApp {
public static void main(String[] args) {
SpringApplication.run(StorageApp.class, args);
}
}
rpc实现类
package com.sid.rpc.service;
import com.sid.rpc.service.service.StorageServiceApi;
import com.sid.service.StorageService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
@Service(group = "storage-provider", version = "1.0.0")
public class StorageServiceRpcImpl implements StorageServiceApi {
@Autowired
private com.sid.service.StorageService StorageService;
/**
* 商品扣库存
* */
@Override
public String deduct(String commodityCode, int count) {
return StorageService.deduct(commodityCode,count);
}
}
业务service实现类
package com.sid.service;
import com.sid.mapper.StorageMapper;
import com.sid.model.Storage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
public class StorageServiceImpl implements StorageService {
@Resource
private StorageMapper storageMapper;
/**
* 商品扣库存
* */
@Override
@Transactional
public String deduct(String commodityCode, int count) {
Storage storage = storageMapper.selectByPrimaryKey(commodityCode);
Integer storageCount = storage.getStorageCount();
storage.setStorageCount(storageCount - count);
int i = storageMapper.updateByPrimaryKey(storage);
//int ii = 1/0;
if(i == 1){
return "success";
}
return "fail";
}
}
StorageServiceApi.java
package com.sid.rpc.service.service;
public interface StorageServiceApi {
String deduct(String commodityCode, int count);
}
http://localhost:8848/
1.Nacos Config 数据结构
Nacos Config 主要通过 dataId 和 group 来唯一确定一条配置.
Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 ConfigService.getConfig(String dataId, String group, long timeoutMs)。
2.Spring Cloud 应用获取数据
dataId
在 Nacos Config Starter 中,dataId 的拼接格式如下
${prefix} - ${spring.profiles.active} . ${file-extension}
prefix 默认为 spring.application.name 的值,也可以通过springboot的application.yml中的配置项 spring.cloud.nacos.config.prefix来配置。
spring.profiles.active 即为当前环境对应的 profile
注意,当 spring.profiles.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成
${prefix}.{file-extension}
file-extension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension来配置。 默认是 properties 类型。
group
group 默认为 DEFAULT_GROUP,可以通过 spring.cloud.nacos.config.group 配置。
默认情况下,会加载命名空间=public,DataID=${spring.application.name}.properties,Group=DEFAULT_GROUP的配置。
3.自动注入
Nacos Config Starter 实现了 org.springframework.cloud.bootstrap.config.PropertySourceLocator接口,并将优先级设置成了最高。
在 Spring Cloud 应用启动阶段,会主动从 Nacos Server 端获取对应的数据,并将获取到的数据转换成 PropertySource 且注入到 Environment 的 PropertySources 属性中,
所以使用 @Value 注解也能直接获取 Nacos Server 端配置的内容。
默认情况下,会加载命名空间=public,DataID=${spring.application.name}.properties,Group=DEFAULT_GROUP的配置。
作为配置中心举例就只以business项目举例了
business项目在前面的代码基础上,加入下面的改动
pom.xml加入
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
2.1.1.RELEASE
bootstrap.yml加入
获取配置中心的配置
这里可以看到,直接用spring的@Value就能读到nacos配置中心的配置了(前提是用springcloud来粘合的)
Nacos Config Starter 实现了 org.springframework.cloud.bootstrap.config.PropertySourceLocator接口,并将优先级设置成了最高。
在Spring Cloud应用启动阶段,会主动从Nacos Server端获取对应的数据,并将获取到的数据转换成PropertySource且注入到Environment的PropertySources属性中,所以使用@Value注解也能直接获取Nacos Server端配置的内容。
package com.sid.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class NacosConfig {
@Value("${business.testConfig}")
private String businessTestConfig;
@Value("${ip}")
private String ip;
public String getBusinessTestConfig() {
return businessTestConfig;
}
public void setBusinessTestConfig(String businessTestConfig) {
this.businessTestConfig = businessTestConfig;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
}
这样子搞,是读的nacos的命名空间public里面的东西
默认情况下,会加载命名空间=public,DataID=${spring.application.name}.properties,Group=DEFAULT_GROUP的配置。
在配置列表public命名空间里面创建1个文件,文件的名字是app-business,这个文件的名字要跟该应用的名字一样,文件格式是properties
app-business内容是
启动的时候从日志就能看到本应用读的是nacos配置中的哪个文件,文件里面有些什么内容
写个controller来请求验证一下读到的配置文件的内容
package com.sid.controller;
//import com.sid.config.NacosConfig;
import com.sid.config.NacosConfig;
import com.sid.model.Business;
import com.sid.service.BusinessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class BusinessController {
@Autowired
BusinessService businessService;
@Autowired
NacosConfig nacosConfig;
/**
* 采购
*/
@RequestMapping(value = "business/purchase",method = RequestMethod.POST)
public void purchase(String userId, String commodityCode, int orderCount) {
businessService.purchase(userId,commodityCode,orderCount);
}
@RequestMapping(value = "business/config",method = RequestMethod.GET)
public NacosConfig config() {
return nacosConfig;
}
}
在nacos的界面创建2个命名空间,一个是dev,
在配置列表中,dev命名空间下,创建配置文件app-business
内容如下
代码
主要是修改bootstrap.yml的配置
加上namespace,注意这里的命名空间不是用名字,不是用dev,而是用它的ID,命名空间的ID
启动日志其实就能看到读到了dev命名空间里面的app-business配置文件中的东西了
在nacos的管理界面加入配置文件application.properties,注意要把后缀.properties写全
内容
主要是修改bootstrap.yml的配置,加一个配置,注意要把后缀.properties写全
启动日志
可以看到去加载了文件application.properties
2021-05-27 16:55:40.361 WARN --- [main] c.a.c.n.c.NacosPropertySourceBuilder Ignore the empty nacos configuration and get it based on dataId[application.properties] & group[DEFAULT_GROUP]
2021-05-27 16:55:40.369 INFO --- [main] c.a.c.n.c.NacosPropertySourceBuilder Loading nacos data, dataId: 'app-business', group: 'DEFAULT_GROUP', data: business.testConfig=dev
ip=12345678
2021-05-27 16:55:40.373 WARN --- [main] c.a.c.n.c.NacosPropertySourceBuilder Ignore the empty nacos configuration and get it based on dataId[app-business.properties] & group[DEFAULT_GROUP]
2021-05-27 16:55:40.373 INFO --- [main] b.c.PropertySourceBootstrapConfiguration Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='app-business.properties'}, NacosPropertySource {name='app-business'}, NacosPropertySource {name='application.properties'}]}
Nacos Config Starter 默认为所有获取数据成功的 Nacos 的配置项添加了监听功能,在监听到服务端配置发生变化时会实时触发 org.springframework.cloud.context.refresh.ContextRefresher 的 refresh 方法 。
如果需要对 Bean 进行动态刷新,给类添加 @RefreshScope 或 @ConfigurationProperties注解。
Springboot支持这一点,Nacos Config也同时可以使用Endpoint来暴露信息。
在maven 中添加 spring-boot-starter-actuator依赖,并在配置中允许 Endpoints 的访问。
org.springframework.boot
spring-boot-starter-actuator
2.1.1.RELEASE
Spring Boot 1.x 中添加配置 management.security.enabled=false
Spring Boot 2.x 中添加配置 management.endpoints.web.exposure.include=*
management:
endpoints:
web:
exposure:
include: '*'
Spring Boot 1.x 可以通过访问 http://127.0.0.1:8085/nacos_config 来查看 Nacos Endpoint 的信息。
Spring Boot 2.x 可以通过访问 http://localhost:8085/actuator/nacos-config 来访问。
在idea中能看到一共有哪些mapping
服务发现的
http://127.0.0.1:8085/actuator/nacos-discovery
配置
nacos作为配置中心,客户端的配置见源码中的NacosConfigProperties类
nacos作为注册中心,客户端的配置见源码中的NacosDiscoveryProperties类
openApi
https://nacos.io/zh-cn/docs/open-api.html
比如查询服务列表
http://localhost:8848/nacos/v1/ns/service/list?pageNo=1&pageSize=100
获取配置
http://localhost:8848/nacos/v1/cs/configs?dataId=app-business&group=DEFAULT_GROUP
发布配置
curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs' -d 'dataId=nacos.example&group=com.alibaba.nacos&content=contentTest'
Nacos的数据库脚本文件在我们下载Nacos-server时的压缩包中就有。
进入nacos-server-1.4.1\nacos\conf目录,里面有个初始化文件:nacos-mysql.sql。
自己在mysql中创建一个nacos 的数据库,然后执行nacos-mysql.sql初始化脚本,成功后会生成一些表。
这里是需要修改Nacos-server的配置文件
Nacos-server其实就是一个Java工程或者说是一个Springboot项目,他的配置文件在nacos-server-1.4.1\nacos\conf目录下,名为 application.properties
把配置文件中关于mysql配置的部分打开,本来是注释了的,填入自己的mysql的IP账号密码:
#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql### Count of DB:
db.num=1### Connect URL of DB:
db.url.0=jdbc:mysql://localhost:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=root### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
先启动Nacos-server,在目录nacos-server-1.4.1\nacos\bin
cmd startup.cmd -m standalone
启动成功后进入Nacos控制台,此时的Nacos控制台中焕然一新,之前的数据都不见了
因为加入了新的数据源,Nacos从mysql中读取所有的配置文件,而我们刚刚初始化的数据库是干干净净的,自然不会有什么数据和信息显示。
添加一些配置
观察数据库nacos中的数据库表 config_info , 如下